时间:2011.6.1 19:58
POJ1638 Picnic Planning (最小限制度生成树)
题意:有一群兄弟去野餐,可以自己开车到目的地,或者开车到A的家里,然后和A一起去目的地。但目的地的停车场不一定容得下,如果每个人都自己开车去的话。所以这对连接到Park的边数有个限制。求他们总路径的最小值。
思路:最小限制度生成树,是指在无向图里找一颗最小生成树,使给定点V0的度数<=k;
步骤:1.先求出最小m度限制生成树:将所有与Park连接的边去掉,得到一个或多个连通分量,各自求其最小生成树。当求出一个最小生成树T时,挑其中一个与Park最近的点,作为T的根,并以他为起点,求T上其他点的father节点。
2.由1,求m+1度限制生成树:先做处理,求出best[]数组,即比如best[3]=2,即3到Park路径上的最大的边权由2及father[2]构成。之后,寻找一点x,使得g[source][x]-g[best[x]][father[bext[x]]]的和最小,并把边{best[x],father[best[x]]}去掉。
3.当为K度限制生成树时,停止。
#include <iostream> #include <cstdio> #include <cstring> #include <map> #define N 30 #define INF (1 << 30) using namespace std; int n, k, s, idx; int vis[N], dis[N], f[N], pre[N], mark[N], best[N]; int g[N][N], edg[N][N]; map<string, int> q; int dfs(int x) { int i; for (i = 1; i <= idx; i++) { if (edg[i][x] && mark[i]) { f[i] = x; mark[i] = 0; dfs(i); } } return 1; } int prim(int x) { int i, j, key, mini, sum = 0, root = -1; for (i = 1; i <= idx; i++) { dis[i] = g[x][i]; pre[i] = x; } //pre[x] = s; memset(mark, 0, sizeof(mark)); vis[x] = 1; mark[x] = 1; while (1) { mini = INF; key = -1; for (i = 1; i <= idx; i++) { if (! vis[i] && ! mark[i] && dis[i] < mini) { mini = dis[i]; key = i; } } if (key == -1) break; vis[key] = 1; mark[key] = 1; edg[pre[key]][key] = edg[key][pre[key]] = 1; sum += dis[key]; for (i = 1; i <= idx; i++) { if (! vis[i] && ! mark[i] && g[key][i] < dis[i]) { dis[i] = g[key][i]; pre[i] = key; } } } mini = INF; for (i = 1; i <= idx; i++) { if (mark[i] && g[s][i] < mini) { mini = g[s][i]; root = i; } } mark[root] = 0; dfs(root); f[root] = s; return sum + mini; } int find_best(int x) { int tmp; if (f[x] == s) return -1; if (best[x] != -1) return best[x]; tmp = find_best(f[x]); if (tmp != -1 && g[f[tmp]][tmp] > g[f[x]][x]) best[x] = tmp; else best[x] = x; return best[x]; } int solve() { int i, j, m = 0, mst = 0, minadd, ax, bx, tmp, change; memset(vis, 0, sizeof(vis)); memset(f, -1, sizeof(f)); memset(edg, 0, sizeof(edg)); vis[s] = 1; for (i = 1; i <= idx; i++) { if (! vis[i]) { mst += prim(i); m++; } } for (i = m + 1; i <= k; i++) { memset(best, -1, sizeof(best)); for (j = 1; j <= idx; j++) { if (best[j] == -1 && f[j] != s) find_best(j); } minadd = INF; for (j = 1; j <= idx; j++) { if (g[s][j] != INF && f[j] != s) { ax = best[j]; bx = f[ax]; tmp = g[s][j] - g[bx][ax]; if (tmp < minadd) { minadd = tmp; change = j; } } } if (minadd >= 0) break; mst += minadd; ax = best[change]; bx = f[ax]; g[ax][bx] = g[bx][ax] = INF; f[ax] = bx = s; g[ax][bx] = g[bx][ax] = g[s][change]; g[s][change] = g[change][s] = INF; } return mst; } int main() { int i, j, d, t1, t2, mst; string s1, s2; scanf("%d", &n); for (i = 1; i <= N - 2; i++) { for (j = 1; j <= N - 2; j++) g[i][j] = INF; } idx = 1; q["Park"] = idx; while (n--) { cin >> s1 >> s2; scanf("%d", &d); if (q.find(s1) == q.end()) t1 = q[s1] = ++idx; else t1 = q[s1]; if (q.find(s2) == q.end()) t2 = q[s2] = ++idx; else t2 = q[s2]; if (d < g[t1][t2]) g[t1][t2] = g[t2][t1] = d; } scanf("%d", &k); s = 1; mst = solve(); printf("Total miles driven: %d/n", mst); system("pause"); return 0; }