https://vjudge.net/problem/UVA-1151
题意:给n个点,连接点i和点j的边的花费为两点的欧几里得距离,有q套构成,可以直接使用对应的花费将套餐中的点加入生成树,也可以直接建边,求最小生成树。
思路:先对n个点进行一次Kruskal,之后对套餐的选中与否进行状态压缩,遍历所有情况即可。
1 #include <bits/stdc++.h> 2 #define fi first 3 #define se second 4 #define pb(i) push_back(i) 5 #define rep(i, a, b) for (int i = a; i <= b; i++) 6 #define per(i, a, b) for (int i = b; i >= a; i--) 7 #define mem(a, b) memset(a, b, sizeof(a)) 8 #define VI vector<int> 9 #define VLL vector<ll> 10 #define MPII map<pair<int, int>, int> 11 #define mp make_pair 12 #define PQI priority_queue<int> 13 #define lowbit(x) x & -x 14 #define debug(a) cout << #a << '=' << a << ' ' 15 using namespace std; 16 typedef long long ll; 17 typedef unsigned long long ull; 18 const int N = 1e6 + 10; 19 const int INF = 0x3f3f3f3f; 20 const int inf = -INF; 21 const int mod = 1e9 + 7; 22 const double pi = acos(-1.0); 23 const double eps = 1e-5; 24 25 int n, q; 26 int p[1005]; 27 int x[1005], y[1005]; 28 vector<int> subn[10]; 29 int cost[10]; 30 int find(int x) 31 { 32 return p[x] == x ? x : p[x] = find(p[x]); 33 } 34 struct Edge 35 { 36 int u, v, d; 37 Edge(int u, int v, int d) : u(u), v(v), d(d){}; 38 bool operator<(const Edge T) const 39 { 40 return d < T.d; 41 } 42 }; 43 int Kruskal(int cnt, vector<Edge> &e, vector<Edge> &res) 44 { 45 if (cnt == 1) 46 return 0; 47 int m = e.size(); 48 int ans = 0; 49 res.clear(); 50 for (int i = 0; i < m; i++) 51 { 52 int u = find(e[i].u), v = find(e[i].v); 53 if (u != v) 54 { 55 ans += e[i].d; 56 p[v] = u; 57 res.push_back(e[i]); 58 if (--cnt == 1) 59 break; 60 } 61 } 62 return ans; 63 } 64 int main() 65 { 66 int T; 67 scanf("%d", &T); 68 while (T--) 69 { 70 scanf("%d%d", &n, &q); 71 for (int i = 0; i < q; i++) 72 { 73 int k; 74 scanf("%d%d", &k, &cost[i]); 75 subn[i].clear(); 76 for (int u, j = 0; j < k; j++) 77 { 78 scanf("%d", &u); 79 subn[i].push_back(u - 1); 80 } 81 } 82 for (int i = 0; i < n; i++) 83 scanf("%d%d", &x[i], &y[i]); 84 vector<Edge> e, need; 85 for (int i = 0; i < n; i++) 86 { 87 for (int j = i + 1; j < n; j++) 88 { 89 int d = (x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]); 90 e.push_back(Edge(i, j, d)); 91 } 92 } 93 for (int i = 0; i < n; i++) 94 p[i] = i; 95 sort(e.begin(), e.end()); 96 int ans = Kruskal(n, e, need); 97 for (int mask = 0; mask < (1 << q); mask++) 98 { 99 for (int i = 0; i < n; i++) 100 p[i] = i; 101 int cnt = n, c = 0; 102 for (int i = 0; i < q; i++) 103 { 104 if (mask & (1 << i)) 105 { 106 c += cost[i]; 107 for (int j = 1; j < subn[i].size(); j++) 108 { 109 int u = find(subn[i][j]), v = find(subn[i][0]); 110 if (u != v) 111 { 112 p[v] = u; 113 cnt--; 114 } 115 } 116 } 117 } 118 vector<Edge> res; 119 ans = min(ans, c + Kruskal(cnt, need, res)); 120 } 121 printf("%d ", ans); 122 if(T) printf(" "); 123 } 124 system("pause"); 125 return 0; 126 }