UVa1151 Buy or Build (最小生成树,枚举子集)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UVa1151 Buy or Build (最小生成树,枚举子集)相关的知识,希望对你有一定的参考价值。

链接:http://bak.vjudge.net/problem/UVA-1151

分析:先在原图上跑一遍MST,得到n-1条边,然后其它的边完全可以抛弃掉,因为它们不会比这n-1条边更优,这样就可以把原图边的数量减少到n-1条,并且得到ans初值。

接下来就是通过枚举套餐子集,生成一个套餐费用c1并且得到若干联通分量,再在这些联通分量基础上跑MST得到最小花费c2,更新答案ans。

 

 1 #include <cstdio>
 2 #include <vector>
 3 #include <algorithm>
 4 using namespace std;
 5 
 6 const int maxn = 1e3 + 5;
 7 const int maxq = 8;
 8 
 9 int n, q, cost[maxn], x[maxn], y[maxn];
10 vector<int> subn[maxq];
11 
12 int pa[maxn];
13 int findset(int x) { return pa[x] != x ? pa[x] = findset(pa[x]) : x; }
14 
15 struct Edge {
16     int u, v, w;
17     Edge(int u, int v, int w): u(u), v(v), w(w) {}
18     bool operator < (const Edge& rhs) const {
19         return w < rhs.w;
20     }
21 };
22 
23 int MST(int cnt, const vector<Edge>& e, vector<Edge>& used) {
24     if (cnt == 1) return 0;
25     int ans = 0;
26     int sz = e.size();
27     for (int i = 0; i < sz; i++) {
28         int u = findset(e[i].u); int v = findset(e[i].v);
29         if (u != v) {
30             pa[u] = v;
31             ans += e[i].w;
32             used.push_back(e[i]);
33             if (--cnt == 1) break;
34         }
35     }
36     return ans;
37 }
38 
39 int main() {
40     int T;
41     scanf("%d", &T);
42     while (T--) {
43         scanf("%d%d", &n, &q);
44         for (int i = 0, cnt, u; i < q; i++) {
45             scanf("%d%d", &cnt, &cost[i]);
46             subn[i].clear();
47             while (cnt--) {
48                 scanf("%d", &u);
49                 subn[i].push_back(u - 1);
50             }
51         }
52         for (int i = 0; i < n; i++) scanf("%d%d", &x[i], &y[i]);
53         vector<Edge> e, need;
54         for (int i = 0; i < n; i++)
55             for (int j = i + 1; j < n; j++) {
56                 int d = (x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]);
57                 e.push_back(Edge(i, j, d));
58             }
59         for (int i = 0; i < n; i++) pa[i] = i;
60         sort(e.begin(), e.end());
61         int ans = MST(n, e, need);
62         for (int mask = 0; mask < (1 << q); mask++) {
63             for (int i = 0; i < n; i++) pa[i] = i;
64             int cnt = n, c = 0;
65             for (int i = 0; i < q; i++) if (mask & (1 << i)) {
66                 c += cost[i];
67                 for (int j = 1; j < subn[i].size(); j++) {
68                     int u = findset(subn[i][j]), v = findset(subn[i][0]);
69                     if (u != v) {
70                         pa[u] = v;
71                         cnt--;
72                     }
73                 }
74             }
75             vector<Edge> dummy;
76             ans = min(ans, c + MST(cnt, need, dummy));
77         }
78         printf("%d\n", ans);
79         if (T) putchar(\n);
80     }
81     return 0;
82 }

 

以上是关于UVa1151 Buy or Build (最小生成树,枚举子集)的主要内容,如果未能解决你的问题,请参考以下文章

uva 1151Buy or Build(图论 最小生成树)

UVa 1151 Buy or Build (最小生成树+二进制法暴力求解)

Buy or Build UVA - 1151

UVA 1151 Buy or build(并查集之六)

UVA 1151 Buy or Build (有某些特别的东东的最小生成树)

[UVA - 1151] Buy or Build 题解