poj 1639 Picnic Planning 度限制mst

https://vjudge.net/problem/POJ-1639

题意:

有一群人,他们要去某一个地方,每个车可以装无数个人,给出了n条路,包含的信息有路连接的地方,以及路的长度,路是双向的,但是终点只有一个,并且终点能停的车的数量是有限制的,问最少走的路是多少。

思路:

因为终点的停车的数量是有限制的,所以终点的度是有限制的,又因为这题可以用最小生成树解决,所以就是度限制最小生成树。

度限制最小生成树求解思想并不复杂,首先我们把有度限制的点给忽略,然后给每一个连通分量求最小生成树,最后把每一个连通分量中与有度限制的点的距离最小的点与度限制点连接,假设有m个连通分量。

那么我们现在求出了m限制的最小生成树,假如限制数k < m,那么就无解。

当k >= m时,我们可以在m度限制mst的基础上,求m + 1,m + 2。。。k度限制最小生成树,求法也不是很难懂,但是程序就很难写了Orz。

如何求呢?枚举每一条未在生成树中与(现在我们把度限制点叫做R点)R点相连的边,然后把边加入生成树,必然会形成环,然后把环中与R点不相连的权值最大的边去掉,枚举之后的最小值就是m+1度限制最小生成树的值。然后依次求到k限制mst,求其中的最小值。

但是,依次枚举的话时间复杂度非常高,所以我们要优化。这时就用到了动态规划的思想。将与R点到其它点的边权值最大求出,之后加边的时候,直接替换就可以了。

转移方程 dp[v] = max(dp[father(v)],w(v , father(v)));

看不懂就多看几遍Orrrrrrrrrrrrrrrrrrrrrrrrz。

代码:

  1 #include <stdio.h>
  2 #include <algorithm>
  3 #include <iostream>
  4 #include <string.h>
  5 #include <map>
  6 #include <string>
  7 using namespace std;
  8 
  9 const int inf = 0x3f3f3f3f;
 10 
 11 struct edge
 12 {
 13     int x,y;
 14     int v;
 15 } a[5055],dp[5055];
 16 
 17 map<string,int> mmp;
 18 bool flag[105][105];
 19 int par[105];
 20 int g[105][105];
 21 
 22 int ans;
 23 int num;
 24 int du,lim;
 25 
 26 int fin(int x)
 27 {
 28     if (x == par[x]) return x;
 29     else return par[x] = fin(par[x]);
 30 }
 31 
 32 void unit(int x,int y)
 33 {
 34     x = fin(x);
 35     y = fin(y);
 36 
 37     if (x == y) return;
 38 
 39     par[x] = y;
 40 }
 41 
 42 void dfs(int cur,int pre)
 43 {
 44     for (int i = 2;i <= num;i++)
 45     {
 46         if (i != pre && flag[cur][i])
 47         {
 48             if (dp[i].v == -1)
 49             {
 50                 if (dp[cur].v > g[cur][i])
 51                 {
 52                     dp[i] = dp[cur];
 53                 }
 54                 else
 55                 {
 56                     dp[i].x = cur;
 57                     dp[i].y = i;
 58                     dp[i].v = g[cur][i];
 59                 }
 60             }
 61 
 62             dfs(i,cur);
 63         }
 64     }
 65 }
 66 
 67 void solve(void)
 68 {
 69     for (int i = du + 1;i <= lim;i++)
 70     {
 71         memset(dp,-1,sizeof(dp));
 72 
 73         dp[1].v = -inf;
 74 
 75         for (int j = 2;j <= num;j++)
 76             if (flag[j][1]) dp[j].v = -inf;
 77 
 78         dfs(1,-1);
 79 
 80         int mi = inf,tmp;
 81 
 82         for (int j = 2;j <= num;j++)
 83         {
 84             if (g[1][j] != -1)
 85             {
 86                 if (mi > g[1][j] - dp[j].v)
 87                 {
 88                     mi = g[1][j] - dp[j].v;
 89                     tmp = j;
 90                 }
 91             }
 92         }
 93 
 94         if (mi >= 0) break;
 95 
 96         ans += mi;
 97 
 98         int x = dp[tmp].x,y = dp[tmp].y;
 99 
100         flag[x][y] = flag[y][x] = 0;
101 
102         flag[1][tmp] = flag[tmp][1] = 1;
103     }
104 }
105 
106 int get_num(string aa)
107 {
108     if (mmp[aa]) return mmp[aa];
109     else
110     {
111         mmp[aa] = ++num;
112         return num;
113     }
114 }
115 
116 bool cmp(edge aa,edge bb)
117 {
118     return aa.v < bb.v;
119 }
120 
121 int main()
122 {
123     num = 1;
124 
125     mmp["Park"] = 1;
126 
127     memset(g,-1,sizeof(g));
128 
129     int n;
130 
131     scanf("%d",&n);
132 
133     for (int i = 0;i < n;i++)
134     {
135         string aa,bb;
136         int v;
137 
138         cin >> aa >> bb;
139 
140         scanf("%d",&v);
141 
142         int x = get_num(aa),y = get_num(bb);
143 
144         if (g[x][y] == -1) g[x][y] = g[y][x] = v;
145         else g[x][y] = g[y][x] = min(v,g[x][y]);
146 
147         a[i].x = x;
148         a[i].y = y;
149         a[i].v = g[x][y];
150     }
151 
152     for (int i = 0;i <= num;i++) par[i] = i;
153 
154     scanf("%d",&lim);
155 
156     sort(a,a+n,cmp);
157 
158     for (int i = 0;i < n;i++)
159     {
160         int x = a[i].x,y = a[i].y;
161 
162         if (x == 1 || y == 1) continue;
163         if (fin(x) == fin(y)) continue;
164 
165         ans += a[i].v;
166 
167         unit(x,y);
168 
169         flag[x][y] = flag[y][x]  =1;
170     }
171 
172     int minn[105],tmp[105];
173 
174     memset(minn,inf,sizeof(minn));
175 
176     for (int i = 2;i <= num;i++)
177     {
178         int rt = fin(i);
179 
180         if (g[1][i] != -1)
181         {
182             if (g[1][i] < minn[rt])
183             {
184                 minn[rt] = g[1][i];
185                 tmp[rt] = i;
186             }
187         }
188     }
189 
190     for (int i = 2;i <= num;i++)
191     {
192         if (minn[i] != inf)
193         {
194             du++;
195             flag[1][tmp[i]] = flag[tmp[i]][1] = 1;
196             ans += minn[i];
197         }
198     }
199 
200     solve();
201 
202     printf("Total miles driven: %d
",ans);
203 
204     return 0;
205 }
原文地址:https://www.cnblogs.com/kickit/p/7415849.html