POJ 1639 Picnic Planning(最小度限制生成树)
Description
The Contortion Brothers are a famous set of circus clowns, known worldwide for their incredible ability to cram an unlimited number of themselves into even the smallest vehicle. During the off-season, the brothers like to get together for an Annual Contortionists Meeting at a local park. However, the brothers are not only tight with regard to cramped quarters, but with money as well, so they try to find the way to get everyone to the party which minimizes the number of miles put on everyone's cars (thus saving gas, wear and tear, etc.). To this end they are willing to cram themselves into as few cars as necessary to minimize the total number of miles put on all their cars together. This often results in many brothers driving to one brother's house, leaving all but one car there and piling into the remaining one. There is a constraint at the park, however: the parking lot at the picnic site can only hold a limited number of cars, so that must be factored into the overall miserly calculation. Also, due to an entrance fee to the park, once any brother's car arrives at the park it is there to stay; he will not drop off his passengers and then leave to pick up other brothers. Now for your average circus clan, solving this problem is a challenge, so it is left to you to write a program to solve their milage minimization problem.
Input
Input will consist of one problem instance. The first line will contain a single integer n indicating the number of highway connections between brothers or between brothers and the park. The next n lines will contain one connection per line, of the form name1 name2 dist, where name1 and name2 are either the names of two brothers or the word Park and a brother's name (in either order), and dist is the integer distance between them. These roads will all be 2-way roads, and dist will always be positive.The maximum number of brothers will be 20 and the maximumlength of any name will be 10 characters.Following these n lines will be one final line containing an integer s which specifies the number of cars which can fit in the parking lot of the picnic site. You may assume that there is a path from every brother's house to the park and that a solution exists for each problem instance.
Output
Output should consist of one line of the form
Total miles driven: xxx
where xxx is the total number of miles driven by all the brothers' cars.
Total miles driven: xxx
where xxx is the total number of miles driven by all the brothers' cars.
题目大意:有一群人开车到某地,但是某地的停车场又只能停k部车。不过呢,这群人可以先开车到另外一个人的家里,然后搭别人的便车(车没有坐人的上限噢,开挂的民族……)到某地。然后呢,他们又很省钱,希望花的钱最少(也就是车驶过的路径最小,因为开车要油嘛等等),问最短距离是多少。(又不告诉你边数上限,也不告诉你有几个人,慢慢算吧……)
思路:最小生成树。如果一个人开车到了另外一个人的地方,肯定会坐别人的车,省钱嘛,所以很容易能看出总路径就是最小生成树,而对某个点的度数有所限制,则对最小度限制生成树稍作修改即可(这题可不一定要停满别人的停车场啊……)。更详细的可以去看2004年 汪汀 的论文《最小生成树问题的拓展》
PS:V好小啊只有20是要闹哪样啊……
PS:没事翻博客的时候发现这代码有BUG,虽然AC了,不过我懒得改了就这样吧……
代码写得有点挫……
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <cstring> 2 #include <string> 3 #include <iostream> 4 #include <cstdio> 5 #include <map> 6 #include <algorithm> 7 using namespace std; 8 9 const int MAXN = 25; 10 const int INF = 0x7f7f7f7f; 11 12 struct Node { 13 int u, v, c, use; 14 Node() {} 15 Node(int uu, int vv, int cc): u(uu), v(vv), c(cc), use(false) {} 16 bool operator < (const Node &rhs) const { 17 return c < rhs.c; 18 } 19 }; 20 21 map<string, int> mymap; 22 string s1, s2; 23 int n, m, k, ecnt, ans, cnt; 24 Node *p; 25 int fa[MAXN], head[MAXN], *next; 26 int mat[MAXN][MAXN]; 27 28 void init() { 29 ecnt = n = 0; 30 p = new Node[2 * m + 5]; 31 next = new int[2 * m + 5]; 32 mymap.clear(); 33 mymap["Park"] = n++; 34 memset(mat, 0, sizeof(mat)); 35 } 36 37 int get_set(int x) { 38 return fa[x] == x ? x : get_set(fa[x]); 39 } 40 41 void add_edge(int u, int v, int c) { 42 p[ecnt++] = Node(u, v, c); 43 p[ecnt++] = Node(v, u, c); 44 if(mat[u][v] == 0 || c < mat[u][v]) 45 mat[u][v] = mat[v][u] = c; 46 } 47 48 void build_link() { 49 memset(head, -1, sizeof(head)); 50 for(int i = ecnt - 1; i >= 0; --i) { 51 next[i] = head[p[i].u]; 52 head[p[i].u] = i; 53 } 54 } 55 56 void kruskal_del0() { 57 ans = cnt = 0; 58 for(int i = 0; i < ecnt; ++i) { 59 if(p[i].u == 0 || p[i].v == 0) continue; 60 int x = get_set(p[i].u), y = get_set(p[i].v); 61 if(x == y) continue; 62 fa[x] = y; 63 p[i].use = p[i ^ 1].use = true; 64 ans += p[i].c; 65 ++cnt; 66 } 67 m = n - 1 - cnt; 68 build_link(); 69 for(int i = head[0]; i != -1; i = next[i]) { 70 if(p[i].u && p[i].v) continue; 71 int x = get_set(p[i].u), y = get_set(p[i].v); 72 if(x == y) continue; 73 fa[x] = fa[y] = 0; 74 p[i].use = p[i ^ 1].use = true; 75 ans += p[i].c; 76 if(++cnt == n - 1) break; 77 } 78 } 79 80 void dfs(int x) { 81 for(int i = head[x]; i != -1; i = next[i]) { 82 if(p[i].use) { 83 fa[p[i].v] = x; 84 p[i].use = p[i ^ 1].use = false; 85 dfs(p[i].v); 86 } 87 } 88 } 89 90 int best[MAXN]; 91 92 int get_best(int x) { 93 if(fa[x] == 0) return -1; 94 if(best[x] != -1) return best[x]; 95 return best[x] = max(mat[x][fa[x]], get_best(fa[x])); 96 } 97 98 void exchange_edge() { 99 while(m++ < k) { 100 memset(best, -1, sizeof(best)); 101 for(int i = 0; i < n; ++i) get_best(i); 102 int a = INF, y = 0; 103 for(int i = head[0]; i != -1; i = next[i]) { 104 if(best[p[i].v] != -1 && a > p[i].c - best[p[i].v]) { 105 a = p[i].c - best[p[i].v]; 106 y = p[i].v; 107 } 108 } 109 if(a >= 0) return ; 110 ans += a; fa[y] = 0; 111 } 112 } 113 114 int main() { 115 int c; 116 while(scanf("%d", &m) != EOF) { 117 init(); 118 while(m--) { 119 cin>>s1>>s2>>c; 120 if(mymap.find(s1) == mymap.end()) mymap[s1] = n++; 121 if(mymap.find(s2) == mymap.end()) mymap[s2] = n++; 122 add_edge(mymap[s1], mymap[s2], c); 123 } 124 scanf("%d", &k); 125 for(int i = 0; i < n; ++i) fa[i] = i; 126 sort(p, p + ecnt); 127 kruskal_del0(); 128 dfs(0); 129 exchange_edge(); 130 printf("Total miles driven: %d\n", ans); 131 delete [] p; 132 delete [] next; 133 } 134 }