您的位置:首页 > 其它

hdu 4126(prim+树形dp)

2014-05-26 18:01 190 查看
题目链接: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++为何就过不了呢。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: