码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2016-09-24 16:01:41      阅读:200      评论:0      收藏:0      [点我收藏+]

标签:

链接: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 (最小生成树,枚举子集)

标签:

原文地址:http://www.cnblogs.com/XieWeida/p/5903227.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!