UVA - 1151 Buy or Build(最小生成树+二进制枚举子集)
2017-05-18 15:16
417 查看
点击打开题目链接
![](https://img-blog.csdn.net/20170518114733923?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbDE4MzI4NzY4MTU=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
题目大意:给出n个点的坐标,连边的费用为两端点的欧几里得距离。给出q种套餐,购买某种套餐花费Ci,该套餐中所有点将连通,求最小花费。
思路:读完题后知道是kruskal最短路问题,但如果枚举所有套餐,又要给所有边排序,又要kruskal,规模太大肯定超时。
所以需要优化:先kruskal求一次得到n-1条边,然后从这n-1条边中用二进制枚举子集的方法枚举套餐。
附上AC代码:
题目大意:给出n个点的坐标,连边的费用为两端点的欧几里得距离。给出q种套餐,购买某种套餐花费Ci,该套餐中所有点将连通,求最小花费。
思路:读完题后知道是kruskal最短路问题,但如果枚举所有套餐,又要给所有边排序,又要kruskal,规模太大肯定超时。
所以需要优化:先kruskal求一次得到n-1条边,然后从这n-1条边中用二进制枚举子集的方法枚举套餐。
附上AC代码:
#include<cstdio> #include<algorithm> using namespace std; const int maxn = 1000+5; typedef long long ll; int T;//T组样例 int n, q;//共n个点,q个套餐 int city_num[8], pack_spend[8];//city_num[]:单个套餐内的点数目 pack_spend[]:套餐花费 int pack_city[8][maxn];//pack_city[]:单个套餐内点的集合 int x[maxn], y[maxn];//坐标 int par[maxn];//根节点 int m, cnt; struct edges { int fr, to, val; bool operator <(const edges & e) { return val < e.val; } }_edge[maxn*maxn],edge[maxn];// //初始化 void init() { for (int i = 0; i <= n; i++)par[i] = i; } //找根节点 int find(int x) { return x == par[x] ? x : par[x] = find(par[x]); } //计算欧几里得距离 int dis(int a, int b) { return (x[a] - x[b])*(x[a] - x[b]) + (y[a] - y[b])*(y[a] - y[b]); } //kruskal ll kruskal() { ll ans = 0; for (int i = 1; i < n; i++) { int dx = find(edge[i].fr); int dy = find(edge[i].to); if (dx != dy) { par[dx] = dy; ans += edge[i].val; } } return ans; } int main() { //ios::sync_with_stdio(false); scanf("%d",&T); while(T--) { cnt = m = 0; //read scanf("%d %d", &n, &q); for (int i = 0; i < q; i++) { scanf("%d%d", & city_num[i], & pack_spend[i]); for (int j = 1; j <= city_num[i]; j++) scanf("%d", & pack_city[i][j]); } for (int i = 1; i <= n; i++) scanf("%d%d", &x[i], &y[i]); //solve init(); for (int i = 1; i <= n; i++) { for (int j = i + 1; j <= n; j++) { _edge[++cnt].fr = i; _edge[cnt].to = j; _edge[cnt].val = dis(i, j); } } //全体点的kruskal ll ans = 0; sort(_edge + 1, _edge + cnt + 1); for (int i = 1; i <= cnt; i++) { int dx = find(_edge[i].fr); int dy = find(_edge[i].to); if (dx != dy) { par[dx] = dy; ans += _edge[i].val; edge[++m] = _edge[i]; } } //套餐的二进制枚举 for (int t = 0; t < (1 << q); t++) { ll anxd = 0; init(); for (int i = 0; i < q; i++) { if (t&(1 << i)) { anxd += pack_spend[i]; for (int j = 2; j <= city_num[i]; j++) par[find(pack_city[i][j-1])] = find(pack_city[i][j]); } } anxd += kruskal(); ans = min(ans, anxd); } printf("%lld\n", ans); if (T)printf("\n"); } // system("pause"); return 0; }
相关文章推荐
- uva-1151-Buy or Build-二进制枚举子集,并查集,最小生成树,kruskal
- UVA 1151 && POJ 2784 - Buy or Build 最小生成树 二进制枚举
- UVA 1151 Buy or Build(最小生成树+枚举子集)
- 紫书例题 11-3 UVa 1151 最小生成树,Kruskal,二进制枚举
- UVA 1151 - Buy or Build(最小生成树,二进制子集生成)
- UVA 1151 Buy or Build 最小生成树+二进制选取子集
- UVA1511 Buy or Build 二进制枚举+最小生成树kruskal
- uva 1151(最小生成树,枚举子集)
- UVa 10807 Prim(最小生成树+二进制枚举)
- [枚举最小瓶颈生成树]UVa-1395 - Slim Span(kruskal)
- 紫书 - UVA - 1151 Buy or Build 最小生成树+状态枚举
- uva 11205 The broken pedometer(暴力枚举+子集生成)
- POJ 2784 Buy or Build(二进制枚举 + 最小生成树)
- 【最小生成树+子集枚举】Uva1151 Buy or Build
- 【UVA】11464-Even Parity(二进制枚举子集)
- Poj(2784),二进制枚举最小生成树
- UVA1151[Buy or Build] 子集枚举+最小生成树
- uva1395 枚举不同区间的最小生成树
- UVA1395 Slim Span(枚举最小生成树)
- 【UVALive】3887 Slim Span 枚举+最小生成树