[暑假集训Day2T3]团建活动

个人认为这周题中较难的一道。

题意大概为:给定一张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 } 
View Code
原文地址:https://www.cnblogs.com/szmssf/p/11172528.html