UVA 1151 Buy or Build (最小生成树)
来源:互联网 发布:华为视频会议软件下载 编辑:程序博客网 时间:2024/05/15 21:50
题意:
告诉你n 个点的坐标,你要在两个点之间连线,使得点全部相同,连边的费用为这两个点的欧几里得距离,你的目的是使这个费用最低,并且你有q(q <= 8) 个套餐可以用,一个套餐中会告诉你一些点已经连通, 问最少花费?
思路:
全部的点相通,很明显是最小生成树。
最容易想到的是,暴力枚举哪一个套餐用,哪一个套餐不用,在求最小生成树,这样会超时,因为原图是一个完全图,有100W个边。
有个小优化:
我们可以先求一边最小生成树,n-1个边,在n-1个边中在暴力枚举套餐。 这样边少了很多很多。
暴力枚举套餐,可以用二进制枚举子集的方法。
#include <cstdio>#include <cstring>#include <algorithm>#include <vector>#include <cmath>#include <cstdlib>#define Siz(x) (int)x.size()#define Max(a,b)((a)>(b)?(a):(b))#define Min(a,b)((a)>(b)?(b):(a))#define ps push_back#define sqr(x)((x)*(x))using namespace std;const int maxn = 1000 + 7;const int inf = 0x3f3f3f3f;typedef long long LL;int T, n, q, num_edge;vector<int>c[10];int w[10],fa[maxn];//double dist[maxn][maxn];struct Node{ int x, y; void read(){ scanf("%d %d",&x, &y); }}nod[maxn];struct edge{ int f,t; int d; int flag; bool operator < (const edge& rhs) const { return d < rhs.d; }}p[maxn*maxn];void addedge(int x,int y,int d){ p[num_edge].f = x; p[num_edge].t = y; p[num_edge].flag = 0; p[num_edge++].d = d;}void DIST(){ num_edge = 0; for (int i = 1; i <= n; ++i){ for (int j = i+1; j <= n; ++j){ int t = (sqr(nod[j].y-nod[i].y) + sqr(nod[j].x-nod[i].x)); addedge(i,j,t); } }}int find(int x){ return fa[x] == x ? fa[x] : fa[x] = find(fa[x]);}void add(int x,int y){ int fx = find(x); int fy = find(y); if (fx != fy){ fa[fx] = fy; }}bool cmp(const edge& lhs, const edge& rhs){ return lhs.flag > rhs.flag;}int solve(int bin){ if (bin == n-1) return 0; int ans = 0; sort(p,p+num_edge); for (int i = 0; i < num_edge; ++i){ int u = p[i].f; int v = p[i].t; if (find(u) != find(v)){ add(u,v); ans += p[i].d; bin++; if (bin == n-1)break; } } return ans;}int main(){ scanf("%d",&T); int ks = 0; while(T--){ scanf("%d %d",&n, &q); LL ans = 0; for (int i = 0; i < 10; ++i)c[i].clear(); for (int i = 1; i <= q; ++i){ int x,y;scanf("%d",&x); scanf("%d",w+i); for (int j = 0; j < x; ++j) { scanf("%d",&y); c[i].ps(y); } } for (int i = 1; i <= n; ++i){ nod[i].read(); } if (ks++)puts(""); DIST(); sort(p,p+num_edge); int bin = 0; for (int i = 1; i <= n; ++i)fa[i] = i; for (int i = 0; i < num_edge; ++i){ int u = p[i].f; int v = p[i].t; if (find(u) != find(v)){ add(u,v); ans += p[i].d; p[i].flag = 1; bin++;// printf(" == %d %d\n",u,v); if (bin == n-1)break; } else p[i].flag = 0; } sort(p,p+num_edge,cmp); num_edge = n-1; for (int i = 0; i < (1<<q); ++i){ int tmp = i; LL sum = 0; int bin2 = 0; for (int j = 1; j <= n; ++j)fa[j] = j; for (int j = 0; j < q; ++j){ int id = q-j; if (tmp & 1){ for (int k = 1; k < Siz(c[id]); ++k){ if (find(c[id][k-1]) != find(c[id][k])){ addedge(c[id][k-1],c[id][k],inf); add(c[id][k-1],c[id][k]); bin2++; } } sum += w[id]; } tmp/=2; } sum += solve(bin2); ans = Min(ans,sum); num_edge = n-1; } printf("%lld\n",ans); } return 0;}/**17 32 4 1 23 3 3 6 73 9 2 4 50 24 02 04 21 30 54 4ans = 17**/
0 0
- uva 1151 Buy or Build (最小生成树)
- UVA 1151 Buy or Build (最小生成树)
- uva 1151 - Buy or Build poj 2784 Buy or Build(最小生成树)
- UVa 1151 Buy or Build (最小生成树)
- UVa 1151 Buy or Build--最小生成树+二进制选择
- UVA 1151 - Buy or Build(最小生成树,二进制子集生成)
- UVA 1151 Buy or Build(最小生成树+枚举子集)
- 1151 - Buy or Build (最小生成树)
- UVA 1151 Buy or Build(生成树+二进制枚举)
- uva-1151-Buy or Build-二进制枚举子集,并查集,最小生成树,kruskal
- UVA 1151 && POJ 2784 - Buy or Build 最小生成树 二进制枚举
- UVA 1151 Buy or Build 最小生成树+二进制选取子集
- Uva1151.Buy or Build (最小生成树)
- uva 1151 Buy or Build
- UVA 1151 Buy or Build
- UVa 1151 Buy or Build
- UVA 1151 Buy or Build
- UVa 1151 Buy or Build
- Samba的命令
- Android中软键盘监听
- 编译器对代码的检查
- 深入理解Java内存模型系列(二)——重排序
- [BZOJ1975]HH去散步 图论+矩阵
- UVA 1151 Buy or Build (最小生成树)
- Flyod在算法题中的应用
- 1024. 科学计数法 (20)
- bug宝典JAVA篇 eclipse中相关问题
- 数三退一的问题解决(C语言和Java实现)
- PHP 7 的五大新特性
- 嵌入式学习:存储器总结
- Ubuntu 下VS Code 调试C代码
- 欢迎使用CSDN-markdown编辑器