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\n",ans); 203 204 return 0; 205 }
康复训练中~欢迎交流!