/*假设两个各自连通的部分分别为树A,树B
1. 用dp[i][j]表示树A中的点i 到 树B(j点所在的树)的最近距离,
这个过程可以在一边dfs就可以出来,对于每个 i 的dfs 复杂度是O(n) ,
外加一个n的循环求出每个点,这里的总复杂度为 O(n^2)。
2. 通过求出来的dp[i][j] 再用一个dfs 求出 树B 到 树A的最近距离,
(方法:枚举树A中的所有点 到 树B的最近距离,取其中的最小值。)
显然, 这个求出来的值是我们要的最小替代边,把它保存到一个best[i][j]数组里面,
(best[i][j]表示去掉边<i,j>后它的最小替代边的值)
这里的总复杂度为 O(n^2)。*/
#include<string.h>
#include<stdio.h>
#include<math.h>
#define N 3005
#define M 9000000
typedef long long LL;
struct edge{
int to,next,w;
}e[N<<1];
int map[N][N],dp[N][N],best[N][N],d[N],head[N],pre[N];
int n,m,ans,mm,inf,o;
bool v[N];
LL anss;
void add(int x,int y)
{ e[o].to=y;
e[o].w=map[x][y];
e[o].next=head[x];
head[x]=o++;
}
bool prim(int s)
{ int i,j,k,ma;
for (i=0;i<n;i++)
{d[i]=map[s][i];
pre[i]=s;
}
memset(v,0,sizeof(v));
v[s]=1;
for (i=1;i<n;i++)
{ma=inf;
for (j=0;j<n;j++)
if (!v[j]&&d[j]<ma) {ma=d[j]; k=j;}
v[k]=1; ans+=d[k];
add(pre[k],k);
add(k,pre[k]);
for (j=0;j<n;j++)
if (!v[j]&&map[k][j]<d[j])
{d[j]=map[k][j];
pre[j]=k;
}
}
return 1;
}
inline int min(int a,int b)
{ return a>b?b:a;
}
void dfs1(int r,int now,int t) //dp[r][now]表示r到 now为根的子树的 最小距离
{ int j;
v[now]=1;
if (t>1)dp[r][now]=map[r][now]; //很关键!
for (int k=head[now];k!=-1;k=e[k].next)
if (!v[e[k].to])
{ j=e[k].to;
v[j]=1;
dfs1(r,j,t+1);
dp[r][now]=min(dp[r][now],dp[r][j]);
}
}
void dfs2(int r,int now,int t) //best[r][now]表示r为根的子树 到 now为根的子树的 最小距离
{ int j;
v[r]=1;
best[r][now]=dp[r][now];//很关键!
for (int k=head[r];k!=-1;k=e[k].next)
if (!v[e[k].to])
{ j=e[k].to;
dfs2(j,now,t+1);
best[r][now]=min(best[r][now],best[j][now]);
}
}
void doit()
{ int i,j,x,y,z;
anss=0; ans=0;
memset(map,0x3F,sizeof(map));
inf=map[0][0];
memset(dp,0x3F,sizeof(dp));
memset(best,0x3F,sizeof(best));
o=0; memset(head,255,sizeof(head));
for (i=0;i<n;i++)
map[i][i]=0;
for (i=1;i<=m;i++)
{scanf("%d%d%d",&x,&y,&z);
if (x==y) continue;
map[x][y]=z;
map[y][x]=z;
}
prim(0);
for (i=0;i<n;i++)
{ memset(v,0,sizeof(v));
dfs1(i,i,0);
}
for (i=0;i<n;i++)
{ memset(v,0,sizeof(v));
dfs2(i,i,0);
}
scanf("%d",&mm);
for (i=1;i<=mm;i++)
{scanf("%d%d%d",&x,&y,&z);
if (pre[x]!=y&&pre[y]!=x)
anss+=ans;//很巧妙
else anss=anss+ans-map[x][y]+min(best[x][y],z);
}
printf("%.4lf\n",double(anss)/mm);
}
int main()
{
while (scanf("%d%d",&n,&m)&&n) doit();
return 0;
}
hdu 4126
最新推荐文章于 2020-11-19 13:14:47 发布