hdu4126(MST + 树形dp

时间:2023-03-10 07:50:04
hdu4126(MST + 树形dp

题意:

      这个题目和hdu4756差不多,是给你一个图,然后是q次改变边的权值,权值只增不减,最后问你每次改变之后的最小树的平均值是多少.

思路:(prim+树形dp)

      先跑一边最小树(建议用普利姆,别用克鲁斯卡尔,虽然网上有用k过的,但我感觉理论上会超时 n*n*nlog(n)/2),然后树形dp跑出任意两个集合之间的最有替代边.(n^2),然后当每次输入一条要该边的边的时候,先判断先是不是最小树上的边,如果不是那么sum直接加最小树,如果是那么就用sum - dis[u][v] + min(dis ,dp[u][v]);就是用原边和不用原边的最小值,记住此时的原边权值已经改变....


#include<stdio.h>
#include<string.h>
#include<algorithm> #define N (3000 + 100)
#define inf 9223372036854775807

using namespace
std; typedef struct
{
int
to ,next;
}
STAR; STAR E[N*2];
int
list[N] ,tot;
double
map[N][N];
double
dp[N][N]; void add(int a ,int b)
{

E[++tot].to = b;
E[tot].next = list[a];
list[a] = tot;
E[++tot].to = a;
E[tot].next = list[b];
list[b] = tot;
} double
minn(double a ,double b)
{
return
a < b ? a : b;
} double
DFS_T_DP(int p ,int s ,int f)
{
double
now = inf;
for(int
k = list[s] ;k ;k = E[k].next)
{
int
to = E[k].to;
if(
to == f) continue;
double
tmp = DFS_T_DP(p ,to ,s);
now = minn(tmp ,now);
dp[s][to] = dp[to][s] = minn(dp[s][to] ,tmp);
}
if(
f != p)
now = minn(now ,map[p][s]);
return
now;
} struct
PRIM //从0开始用
{
double
d[N];int vis[N];
bool
mp[N][N]; //标记最小生成树上的边
double ans;//最小树
int n;//点的个数 记得初始化 ***
double dis[N][N]; // 距离 记得初始化 *****
void prim()
{
for(int
i=0;i<n;i++)
{

vis[i]=0;
d[i]=dis[0][i];
}

vis[0]=-1;
ans=0;
memset(mp,0,sizeof(mp));
for(int
i=1;i<n;i++)
{
double
Min= inf;
int
node=-1;
for(int
j=0;j<n;j++)
{
if(
vis[j]!=-1 && d[j]<Min)
{

node=j;
Min=d[j];
}
}
ans+=Min;
mp[vis[node]][node]=mp[node][vis[node]]=1;
add(vis[node],node); // 建树
vis[node]=-1; for(int j=0;j<n;j++)
{
if(
vis[j]!=-1 && d[j]>dis[node][j])
{

vis[j]=node;
d[j]=dis[node][j];
}
}
}
}
}
P; int main ()
{
int
n ,m ,q ,i ,j ,a ,b;
double
dis;
while(~
scanf("%d %d" ,&n ,&m) && n + m)
{
for(
i = 0 ;i <= n ;i ++)
{
for(
j = i + 1 ;j <= n ;j ++)
P.dis[i][j] = P.dis[j][i] = map[i][j] = map[j][i] = dp[i][j] = dp[j][i] = inf;
P.dis[i][i] = P.dis[i][i] = map[i][i] = map[i][i] = 0;
}
for(
i = 1 ;i <= m ;i ++)
{

scanf("%d %d %lf" ,&a ,&b ,&dis);
map[a][b] = map[b][a] = dis;
P.dis[a][b] = P.dis[b][a] = dis;
}

P.n = n;
memset(list ,0 ,sizeof(list));
tot = 1;
P.prim();
double
T_sum = P.ans;
for(
i = 0 ;i < n ;i ++)
DFS_T_DP(i ,i ,-1);
double
ans_sum = 0;
scanf("%d" ,&q);
for(
i = 1 ;i <= q ;i ++)
{

scanf("%d %d %lf" ,&a ,&b ,&dis);
double
now;
if(!
P.mp[a][b])
now = T_sum ;
else
{
if(
dis > dp[a][b])
now = T_sum - map[a][b] + dp[a][b] ;
else
now = T_sum - map[a][b] + dis ;
}
ans_sum += now;
}

printf("%.4lf\n" ,ans_sum / q);
}
return
0;
}