题意:
n个点,m个边,然后给出m条边的顶点和权值,其次是q次替换,每次替换一条边,给出每次替换的边的顶点和权值,然后求出这次替换的最小生成树的值;
最后要你输出:q次替换的平均值。其中n<3000,q<10000。
分析:
我们可以先求最小生成树,对于最小生成树的每一条边,我们要找到它的最佳替代边,使其价值最小。
具体实践方法:
树形dp,从每个点dfs一次,每次把i当成根,其余都是它的孩子,更新dp数组,对于i点为根的除j之外的所有的
子树中的所有点到j距离最小值。每次从一个点root开始dfs,搜索到最后一个叶子,开始看G[root][u]的大小,保证(root,u)
不是MST上的的边,那么一路返回,连接叶子节点的那条边的最佳替换边就是G[root][u]的大小,再继续返回,
此过程要看,map[root][...]的大小,其中[...]表示从叶子节点一路返回过来的点。
// File Name: 1504.cpp // Author: Zlbing // Created Time: 2013/6/17 19:36:53 #include<iostream> #include<string> #include<algorithm> #include<cstdlib> #include<cstdio> #include<set> #include<map> #include<vector> #include<cstring> #include<stack> #include<cmath> #include<queue> using namespace std; #define CL(x,v); memset(x,v,sizeof(x)); #define INF 0x3f3f3f3f #define LL long long #define REP(i,r,n) for(int i=r;i<=n;i++) #define RREP(i,n,r) for(int i=n;i>=r;i--) const int MAXN=3050; struct Edge{ int u,v,cost; bool operator <(const Edge &rsh)const{ return cost<rsh.cost; } }; vector<Edge>edges; vector<int> mst[MAXN]; int gmst[MAXN][MAXN]; int f[MAXN]; int dp[MAXN][MAXN]; int G[MAXN][MAXN]; int n,m,Q; int ans=0; int find(int x) { return f[x]==x?x:f[x]=find(f[x]); } void kruscal() { ans=0; CL(gmst,0); for(int i=0;i<=n;i++)f[i]=i; for(int i=0;i<m;i++) { Edge e=edges[i]; int fu=find(e.u); int fv=find(e.v); if(fu!=fv) { ans+=e.cost; f[fu]=fv; mst[e.u].push_back(e.v); mst[e.v].push_back(e.u); gmst[e.u][e.v]=gmst[e.v][e.u]=1; } } } int dfs(int root,int u,int fa) { int s=INF; for(int i=0;i<mst[u].size();i++) { int v=mst[u][i]; if(v==fa)continue; int tmp=dfs(root,v,u); s=min(s,tmp); dp[u][v]=dp[v][u]=min(dp[u][v],tmp); } if(root!=fa)//保证这条边不是生成树的边 s=min(s,G[root][u]); return s; } int main() { while(~scanf("%d%d",&n,&m)) { if(n==0)break; edges.clear(); int a,b,c; REP(i,0,n)mst[i].clear(); for(int i=0;i<n;i++) for(int j=0;j<n;j++) { dp[i][j]=INF; G[i][j]=INF; } REP(i,1,m) { scanf("%d%d%d",&a,&b,&c); edges.push_back((Edge){a,b,c}); G[a][b]=G[b][a]=c; } sort(edges.begin(),edges.end()); kruscal(); REP(i,0,n-1) dfs(i,i,-1); int sum=0; scanf("%d",&Q); REP(i,1,Q) { scanf("%d%d%d",&a,&b,&c); if(!gmst[a][b]) sum+=ans; else sum+=ans*1.0-G[a][b]+min(dp[a][b],c); } double s=sum/(double)Q; printf("%.4lf ",s); } return 0; }