[UVA - 1151] Buy or Build 题解
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[UVA - 1151] Buy or Build 题解相关的知识,希望对你有一定的参考价值。
此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置。
题目链接(vjudge):https://vjudge.net/problem/UVA-1151
题目大意:
要把n个城市用网络连接起来。直接或间接连通均可。
每次你可以选择新建一条网络连接两个城市,花费为这两个城市的欧几里得距离。
你也可以选择购买一份已有的网络套餐,花费为Ci元,套餐内的所有城市都会连通。
问最少需要花费多少元。
第一行有一个数T,表示数据组数。
接下来每组数据,第一行有两个数n,k,表示城市数量和套餐数量。(1<=n<=1000,0<=k<=8)
第二行至第k+1行,描述套餐的相关数据。
每行第一个数m表示该套餐内的城市数,第二个数Ci表示该套餐的价格,接下来m个数表示该套餐内的城市。
第k+2行到第k+2+n行,每行两个整数x,y,表示第i个城市的坐标。
输出时,每行输出一个答案,两个答案之间空一行。最后一个答案不空行。
这个辣鸡输出格式要求害我改了好久。辣鸡样例只有一组数据,根本看不出输出要求。
而且如果你少换行了是有可能WA的(我的提交记录一次PE一次WA,但其实都是PE),就很难查错...
Sample Input
1
7 3
2 4 1 2
3 3 3 6 7
3 9 2 4 5
0 2
4 0
2 0
4 2
1 3
0 5
4 4
Sample Output
17
分析:
在没有套餐的情况下求一次最小生成树,然后枚举每一份套餐选不选,把套餐的边加进去,重新做最小生成树。
所有情况的费用取Min更新答案即可。
k不超过8,枚举时用二进制表示当前套餐是否使用。
复杂度O(nlogn+n*2^k)。
AC代码:(惨烈的Debug痕迹..)
1 #include<cstdio> 2 #include<algorithm> 3 #include<cmath> 4 #include<cstring> 5 #include<iostream> 6 7 inline void read(int &x) 8 { 9 char ch = getchar(),c = ch;x = 0; 10 while(ch < ‘0‘ || ch > ‘9‘) c = ch,ch = getchar(); 11 while(ch <= ‘9‘ && ch >= ‘0‘) x = (x<<1)+(x<<3)+ch-‘0‘,ch = getchar(); 12 if(c == ‘-‘) x = -x; 13 } 14 15 int Case,n,m,k,v,cnt,fa[1002]; 16 long long ans; 17 18 inline int find(int x) 19 {return fa[x]==x?x:fa[x]=find(fa[x]);} 20 21 bool merge(int x,int y) 22 { 23 x = find(x),y = find(y); 24 if(x != y) 25 { 26 fa[x] = y; 27 return true; 28 } 29 return false; 30 } 31 32 inline long long Min(long long x,long long y) 33 {return x<y?x:y;} 34 35 struct SET 36 { 37 int m,cost; 38 int mem[1002]; 39 }s[10]; 40 41 struct CITY 42 { 43 int x,y,v; 44 }c[1002],e[1000002],New[1002]; 45 46 int cmp(CITY a,CITY b) 47 {return a.v < b.v;} 48 49 int dis(int i,int j) 50 { 51 int r = (c[i].x-c[j].x)*(c[i].x-c[j].x); 52 r += (c[i].y-c[j].y)*(c[i].y-c[j].y); 53 return r; 54 } 55 56 void init() 57 { 58 cnt = 0;ans = 0; 59 for(int i=1;i<=n;++i) fa[i] = i; 60 } 61 62 int main() 63 { 64 // freopen("1.txt","r",stdin); 65 read(Case); 66 while(Case --) 67 { 68 read(n),read(k); 69 init(); 70 for(int i = 1;i <= k;++ i){ 71 read(s[i].m),read(s[i].cost); 72 for(int j = 1;j <= s[i].m;++ j) 73 read(s[i].mem[j]); 74 } 75 for(int i = 1;i <= n;++ i) 76 read(c[i].x),read(c[i].y); 77 for(int i = 1;i <= n;++ i) 78 for(int j = i+1;j <= n;++ j) 79 { 80 v = dis(i,j); 81 e[++cnt] = (CITY){i,j,v}; 82 } 83 std::sort(e+1,e+1+cnt,cmp); 84 m = cnt;cnt = 0; 85 // for(int i = 1;i <= m;++ i) 86 // printf("%d %d %d \n",e[i].x,e[i].y,e[i].v); 87 for(int i = 1;i <= m;++ i) 88 { 89 if(merge(e[i].x,e[i].y)){ 90 ans += 1LL*e[i].v,cnt ++; 91 New[cnt] = e[i]; 92 } 93 if(cnt == n-1) break; 94 } 95 for(int tmp = 0;tmp < (1<<k);++ tmp) 96 { 97 long long cost = 0; 98 for(int i = 1;i <= n;++ i) fa[i] = i; 99 100 for(int i = 0;i < k;++ i) 101 if(tmp&(1<<i)){ 102 cost += 1LL*s[i+1].cost; 103 for(int j = 2;j <= s[i+1].m;++ j) 104 fa[find(s[i+1].mem[j-1])] = fa[find(s[i+1].mem[j])]; 105 } 106 for(int i = 1;i < n;++ i) 107 if(merge(New[i].x,New[i].y)) 108 cost += 1LL*New[i].v; 109 ans = Min(ans,cost); 110 // printf("%d\n",cost); 111 } 112 printf("%lld\n",ans); 113 if(Case) printf("\n"); 114 } 115 return 0; 116 }
以上是关于[UVA - 1151] Buy or Build 题解的主要内容,如果未能解决你的问题,请参考以下文章
UVa 1151 - Buy or Build(最小生成树)
UVa1151 Buy or Build (最小生成树,枚举子集)
uva 1151Buy or Build(图论 最小生成树)