hdu 4126(prim+树形dp)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4126

思路:我们可以先求最小生成树,对于最小生成树的每一条边,我们要找到它的最佳替代边,使其价值最小。

具体实践方法:

假设两个各自连通的部分分别为树A,树B,dp[i][j]表示树A中的点i到树B(点j所在的树的最近距离),这个很容易用dfs实现,然后通过求出的dp[i][j],再用一个dfs求出树B到树A的最近距离(就是枚举树A中的所有点 到 树B的最近距离,取其中的最小值),这个求出来的值其实就是我们要求的最佳替代边,将它保存到一个数组中即可。总的时间复杂度为O(n^2)。

  1 #include<iostream>

  2 #include<cstdio>

  3 #include<cstring>

  4 #include<algorithm>

  5 #include<vector>

  6 using namespace  std;

  7 #define MAXN 3030

  8 #define inf  1000000000

  9 typedef __int64 LL;

 10 vector<int>edge[MAXN];

 11 int map[MAXN][MAXN];

 12 int lowcost[MAXN];

 13 int nearvex[MAXN];

 14 int n,m,q;

 15 LL sumweight;

 16 int dp[MAXN][MAXN];//树A中的i点到树B中的点j的最近距离

 17 int mindist[MAXN][MAXN];//保存最佳替换边

 18 bool mark[MAXN];

 19 

 20 void Prim(int u0)

 21 {

 22     memset(mark,false,(n+2)*sizeof(int));

 23     for(int i=1;i<n;i++){

 24         lowcost[i]=map[u0][i];

 25         nearvex[i]=u0;

 26     }

 27     mark[u0]=true;

 28     lowcost[u0]=inf;

 29     nearvex[u0]=-1;

 30     sumweight=0;

 31     for(int i=0;i<n-1;i++)

 32     {

 33         int min=inf,v=-1;

 34         for(int j=1;j<n;j++){

 35             if(!mark[j]&&lowcost[j]<min){

 36                 v=j,min=lowcost[j];

 37             }

 38         }

 39         sumweight+=lowcost[v];

 40         mark[v]=true;

 41         if(v!=-1)

 42         {

 43             edge[v].push_back(nearvex[v]);

 44             edge[nearvex[v]].push_back(v);

 45             for(int j=1;j<n;j++)

 46             {

 47                 if(!mark[j]&&map[v][j]<lowcost[j]){

 48                     lowcost[j]=map[v][j];

 49                     nearvex[j]=v;

 50                 }

 51             }

 52         }

 53     }

 54 }

 55 

 56 int dfs1(int u,int father,int rt)

 57 {

 58     for(int i=0;i<edge[u].size();i++){

 59         int v=edge[u][i];

 60         if(v==father)continue;

 61         dp[rt][u]=min(dp[rt][u],dfs1(v,u,rt));

 62     }

 63     if(father!=rt)dp[rt][u]=min(dp[rt][u],map[rt][u]);

 64     return dp[rt][u];

 65 }

 66 

 67 int dfs2(int u,int father,int rt)

 68 {

 69     int ans=dp[u][rt];

 70     for(int i=0;i<edge[u].size();i++){

 71         int v=edge[u][i];

 72         if(v==father)continue;

 73         ans=min(ans,dfs2(v,u,rt));

 74     }

 75     return ans;

 76 }

 77 

 78 void Solve()

 79 {

 80     int u,v,w;

 81     scanf("%d",&q);

 82     double ans=0;

 83    // for(int i=0;i<n;i++)printf("%d***\n",nearvex[i]);

 84     for(int i=1;i<=q;i++)

 85     {

 86         scanf("%d%d%d",&u,&v,&w);

 87         if(nearvex[u]!=v&&nearvex[v]!=u){

 88             ans+=sumweight*1.0;

 89         }else {

 90             ans+=sumweight*1.0-map[u][v]+min(mindist[u][v],w);

 91         }

 92     }

 93     printf("%.4lf\n",ans/q);

 94 }

 95 

 96 

 97 int main()

 98 {

 99     int u,v,w;

100     while(scanf("%d%d",&n,&m),(n+m))

101     {

102         for(int i=0;i<n;i++)edge[i].clear();

103         for(int i=0;i<n;i++)

104             for(int j=0;j<n;j++)

105                 map[i][j]=dp[i][j]=inf;

106         for(int i=0;i<m;i++){

107             scanf("%d%d%d",&u,&v,&w);

108             map[u][v]=map[v][u]=w;

109         }

110         Prim(0);

111         for(int i=0;i<n;i++)

112             dfs1(i,-1,i);

113         for(int i=0;i<n;i++){

114             for(int j=0;j<edge[i].size();j++)

115             {

116                 int v=edge[i][j];

117                 mindist[i][v]=mindist[v][i]=dfs2(v,i,i);

118             }

119         }

120         Solve();

121     }

122     return 0;

123 }
View Code

ps:hdoj上G++能过,但不知C++为何就过不了呢。

你可能感兴趣的:(Prim)