个人认为这周题中较难的一道。
题意大概为:给定一张N个点M条边的无向图,求出无向图的一棵最小生成树,满足一号节点的度数不超过给定的整数K。保证 N <= 20
首先用map存取节点,之后抛去1号节点,求每一个联通分量的MST,就得到了一个局部最优解,设p为联通块的个数,接下来从每一个联通分量中找一个离1号节点距离最近的点,连接其与1号节点的边,就得到了一棵1号节点度数为p的生成树,之后逐渐放宽限制,枚举最终答案的度数,每次从1号节点往其他点连边,会形成一个环,求出该点到1路径上形成的环中边权最大值,之后把这个最大值剪断,将1号节点和该点连边。直到减小不了权值为止
下面给出标程(Author:????)
1 #include <map> 2 #include <cstdio> 3 #include <string> 4 #include <vector> 5 #include <cstring> 6 #include <iostream> 7 #include <algorithm> 8 using namespace std; 9 const int N = 37, INF = 0x3f3f3f3f; 10 struct E { 11 int x, y, z; 12 bool operator < (const E w) const 13 { 14 return z < w.z; 15 } 16 17 }f[N]; 18 int n, k, tot, ans, a[N][N], fa[N], d[N], v[N]; 19 map<string, int> m; 20 vector<E> e; 21 bool b[N][N]; 22 23 int get(int x) { 24 if (x == fa[x]) return x; 25 return fa[x] = get(fa[x]); 26 } 27 // dfs(1,-1) 28 void dfs(int x, int o) { 29 for (int i = 2; i <= tot; i++) { 30 if (i == o || b[x][i]==0) continue; 31 if (f[i].z == -1) { 32 if (f[x].z > a[x][i]) f[i] = f[x]; 33 else { 34 f[i].x = x; 35 f[i].y = i; 36 f[i].z = a[x][i]; 37 } 38 } 39 dfs(i, x); 40 } 41 } 42 43 int main() { 44 cin >> n; 45 memset(a, 0x3f, sizeof(a)); 46 memset(d, 0x3f, sizeof(d)); 47 m["Park"] = tot = 1; 48 for (int i = 0; i < N; i++) fa[i] = i; 49 for (int i = 1; i <= n; i++) { 50 E w; 51 string s1, s2; 52 cin >> s1 >> s2 >> w.z; 53 w.x = m[s1] ? m[s1] : (m[s1] = ++tot); 54 w.y = m[s2] ? m[s2] : (m[s2] = ++tot); 55 e.push_back(w); 56 a[w.x][w.y] = a[w.y][w.x] = w.z; 57 } 58 cin >> k; 59 sort(e.begin(), e.end()); 60 for (unsigned int i = 0; i < e.size(); i++) { 61 if (e[i].x == 1 || e[i].y == 1) continue; 62 int rtx = get(e[i].x), rty = get(e[i].y); 63 if (rtx != rty) { 64 fa[rtx] = rty; 65 b[e[i].x][e[i].y] = b[e[i].y][e[i].x] = 1; 66 ans += e[i].z; 67 } 68 } 69 for (int i = 2; i <= tot; i++) 70 if (a[1][i] != INF) { 71 int rt = get(i); 72 if (d[rt] > a[1][i]) 73 d[rt] = a[1][v[rt]=i]; // 记下每个父节点对应的边缘点以及边缘点和1号点的权值 74 } 75 for (int i = 1; i <= tot; i++) 76 if (d[i] != INF) { 77 --k; 78 b[1][v[i]] = b[v[i]][1] = 1; 79 ans += a[1][v[i]]; 80 } 81 //cout<<k<<endl; 82 while (k--) { 83 memset(f, -1, sizeof(f)); 84 f[1].z = -INF; 85 for (int i = 2; i <= tot; i++) 86 if (b[1][i]) f[i].z = -INF; 87 dfs(1, -1); 88 int o, w = -INF; 89 for (int i = 2; i <= tot; i++) 90 if (w < f[i].z - a[1][i]) 91 w = f[i].z - a[1][o=i]; 92 if (w <= 0) break; 93 //cout<<o<<endl; 94 b[1][o] = b[o][1] = 1; 95 b[f[o].x][f[o].y] = b[f[o].y][f[o].x] = 0; 96 ans -= w; 97 } 98 printf("Total miles driven: %d ", ans); 99 return 0; 100 }