题目链接:HDU4126
好题
最小生成树+离线处理
对于生成树上的u->v这条边,我们考虑删去u->v后,u和v会构成两棵树,我们从v开始遍历v所在的这棵树,每次更新记录dp[u][v]即可
离线处理的复杂度为
O
(
n
2
)
O(n^2)
O(n2)
代码部分挺乱的,有时间再整理
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map>
#include <queue>
#include <functional>
#include <vector>
#include <stack>
#include <set>
//#define int long long
using namespace std;
typedef long long ll;
const int maxn=1e5+50;
const int inf=0x3f3f3f3f;
const int MOD=1e9+7;
const int HASH=131;
struct node
{
int to,val;
};
struct eh
{
int x,y,val;
friend bool operator<(eh a,eh b)
{
return a.val<b.val;
}
}e[3000*3007];
vector<node> edge[3007];
vector<int> ed[3007];
int n,m;
int mp[3007][3007];
int dp[3007][3007];
int vis[3007][3007];
int dis[maxn];
int pre[maxn];
int FIND(int x)
{
return x==pre[x]?x:pre[x]=FIND(pre[x]);
}
int kru()//其实也可以拿prime写,主要是要记录树的路径,直接用kru方便点
{
int ans=0;
for(int i=1;i<=m;i++)
{
int xx=FIND(e[i].x);
int yy=FIND(e[i].y);
if(xx!=yy)
{
pre[xx]=yy;
ans+=e[i].val;
vis[e[i].x][e[i].y]=vis[e[i].y][e[i].x]=1;
ed[e[i].x].push_back(e[i].y);
ed[e[i].y].push_back(e[i].x);//记录生成树路径
}
}
return ans;
}
int dfs(int pos,int u,int fa)
{
int ans=inf;
for(int i=0;i<ed[u].size();i++)
{
int v=ed[u][i];
if(fa==v) continue;
int minn=dfs(pos,v,u);
ans=min(minn,ans);
dp[u][v]=dp[v][u]=min(dp[u][v],minn);
}
if(fa!=pos) ans=min(ans,mp[pos][u]);//保证该路径不是被删除边
return ans;
}
signed main()
{
while(scanf("%d %d",&n,&m)!=EOF&&(n+m))
{
for(int i=1;i<=n;i++)
{
pre[i]=i;
ed[i].clear();
for(int j=1;j<=n;j++)
{
dp[i][j]=inf;
mp[i][j]=inf;
vis[i][j]=0;
}
}
for(int i=1;i<=m;i++)
{
int a,b,c;
cin>>a>>b>>c;
a++,b++;
mp[a][b]=c;
mp[b][a]=c;
e[i].x=a;
e[i].y=b;
e[i].val=c;
}
sort(e+1,e+1+m);
int t,q;
cin>>t;
q=t;
int tree=kru();
double ans=0;
for(int i=1;i<=n;i++)
{
dfs(i,i,-1);
}
while(t--)
{
int a,b,c;
cin>>a>>b>>c;
a++,b++;
if(!vis[a][b])
{
ans+=tree;
}
else
{
ans+=tree-mp[a][b]+min(c,dp[a][b]);
}
}
printf("%.4f\n",ans/(double)q);
}
return 0;
}