首页 > 代码库 > UVa1151&POJ2784--Buy or Build【kruskal+二进制枚举】
UVa1151&POJ2784--Buy or Build【kruskal+二进制枚举】
链接:
UVa http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3592
POJ http://poj.org/problem?id=2784
题意:告诉你n个点的坐标,建立一颗最小生成树,不过有q个套餐,套餐是连通某些点,并有一定花费,求最小生成树。
思路:n个点,n最大为1000,则最多有1000*999/2条边,先不使用套餐求一遍最小生成树,保留下最小生成树的边,此时最多有999条边,然后枚举每种套餐选或者不选,因为只有两种情况,用二进制枚举就行了,然后从筛选出的最多999条边里选边构造最小生成树。
#include<cstring> #include<string> #include<fstream> #include<iostream> #include<iomanip> #include<cstdio> #include<cctype> #include<algorithm> #include<queue> #include<map> #include<set> #include<vector> #include<stack> #include<ctime> #include<cstdlib> #include<functional> #include<cmath> using namespace std; #define PI acos(-1.0) #define MAXN 5000100 #define eps 1e-7 #define INF 0x7FFFFFFF #define LLINF 0x7FFFFFFFFFFFFFFF #define seed 131 #define MOD 1000000007 #define ll long long #define ull unsigned ll #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 struct node{ int u,v; int w; }edge[MAXN],edge2[1010]; int n,m,q,ans; int qc[10][1010],qn[10],qm[10]; int x[1010],y[1010],father[1010]; bool cmp(node x,node y){ return x.w<y.w; } int Find(int x){ int t = x; while(t!=father[t]) t = father[t]; int k = x; while(k!=t){ int temp = father[k]; father[k] = t; k = temp; } return t; } void init(){ for(int i=0;i<=n;i++) father[i] = i; } int kruskal(){ int i,j; int sum = 0; int tot = 0; for(i=0;i<m;i++){ int a = Find(edge[i].u); int b = Find(edge[i].v); if(a!=b){ father[a] = b; edge2[sum] = edge[i]; tot += edge[i].w; sum++; if(sum>=n-1) break; } } return tot; } int gao(int x){ int i,j; int sum = 0; int tot = 0; for(i=0;i<q;i++){ if(x&(1<<i)){ tot += qm[i]; for(j=0;j<qn[i]-1;j++){ int aa = Find(qc[i][j]); int bb = Find(qc[i][j+1]); if(aa!=bb){ father[aa] = bb; sum++; } } } } for(i=0;i<n-1;i++){ int aa = Find(edge2[i].u); int bb = Find(edge2[i].v); if(aa!=bb){ father[aa] = bb; sum++; tot += edge2[i].w; if(sum>=n-1) break; } } //cout<<tot<<endl; return tot; } int main(){ int t,i,j; scanf("%d",&t); for(int iii=0;iii<t;iii++){ if(iii) puts(""); m = 0; scanf("%d%d",&n,&q); for(i=0;i<q;i++){ scanf("%d%d",&qn[i],&qm[i]); for(j=0;j<qn[i];j++){ scanf("%d",&qc[i][j]); } } for(i=1;i<=n;i++){ scanf("%d%d",&x[i],&y[i]); for(j=1;j<i;j++){ int temp = (x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]); edge[m].u = i; edge[m].v = j; edge[m].w = temp; m++; } } sort(edge,edge+m,cmp); init(); ans = kruskal(); for(i=0;i<(1<<q);i++){ init(); int temp = gao(i); ans = min(ans,temp); } printf("%d\n",ans); } return 0; }
UVa1151&POJ2784--Buy or Build【kruskal+二进制枚举】
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。