题意:
这个题目和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;
}