UVA 1151Buy or Build MST(最小生成树)
題意:
在平面上有n個(gè)點(diǎn),要讓所有n個(gè)點(diǎn)都連通,所以你要構(gòu)造一些邊來(lái)連通他們,連通的費(fèi)用等于兩個(gè)端點(diǎn)的歐幾里得距離的平方。另外還有q個(gè)套餐,可以購(gòu)買,如果你購(gòu)買了第i個(gè)套餐,該套餐中的所有結(jié)點(diǎn)將變得相互連通,第i個(gè)套餐的花費(fèi)為ci。求最小花費(fèi)。
思路:
在這里我們可以采取枚舉所有可能 + K算法來(lái)得出答案,比如這里有三個(gè)套餐,我們利用二進(jìn)制枚舉 001、010、011 、100、 101、 110、 111 分別代表第一個(gè)和第二個(gè)不要,要第三個(gè)(001);不要第一個(gè)和第三個(gè),要第二個(gè)(010).......即 0 代表不要, 1 代表要,然后把要的套餐中的所有點(diǎn)都連通,再用K算法求剩下的未連接的點(diǎn)的最小生成樹。
注意:
在套餐中合并點(diǎn)時(shí)不能單純地讓pre[i] = pre[1](i > 1);pre[i]數(shù)組代表 pre[i] 和 i 在一個(gè)集合里面(并查集);舉個(gè)栗子:
有一個(gè)套餐是:
4 10 ?2 3 4 5
含義是購(gòu)買這個(gè)套餐中可以讓四個(gè)點(diǎn)連通,分別是2,3,4,5號(hào)點(diǎn),費(fèi)用為 10;如果讓 pre[3] = pre[4]=pre[5] = 2;
那么假設(shè)還有個(gè)套餐:
3 9 1 5 3?
含義如上 ,如果再寫pre[5] = pre[3] = 1;那么假設(shè)我購(gòu)買了這倆個(gè)套餐,本應(yīng)該2 3 4 5 1都在一個(gè)集合里面的,但是按照上面那么寫 則 2 4 是一個(gè)集合, 1 3 5 是一個(gè)集合。不符合我的意思,所以購(gòu)買套餐合并里面的點(diǎn)時(shí)應(yīng)該寫成pre[i] = Find(pre[1]);前提是這倆個(gè)不在一個(gè)集合里面。
代碼:
1 #include <bits/stdc++.h> 2 #define prln(x) cout<<(x)<<endl 3 using namespace std; 4 typedef long long LL; 5 6 const double PI = acos(-1); 7 const double ESP = 1e-8; 8 const int MAXN = 1000 + 3; 9 const int MOD = 1e9 + 7; 10 int pre[MAXN]; 11 12 typedef struct Point{ //題目中給的點(diǎn) 13 int x; 14 int y; 15 }Po; 16 17 typedef struct Buy{ //套餐 18 int m; //購(gòu)買該套餐可以合并點(diǎn)的個(gè)數(shù) 19 int ci; //購(gòu)買該套餐的費(fèi)用 20 int a[MAXN]; //這個(gè)套餐可以合并的點(diǎn)的編號(hào) 21 int flag; //是否要購(gòu)買這個(gè)套餐,對(duì)每個(gè)套餐的這個(gè)值進(jìn)行二進(jìn)制枚舉 22 }Bu; 23 24 typedef struct City{ //用來(lái)存儲(chǔ)圖 25 int u; 26 int v; 27 int w; 28 }Ci; 29 30 Ci edge[MAXN * MAXN / 2 + 3]; 31 Po pt[MAXN]; 32 Bu buy[11]; 33 34 int Find(int x) //并查集 35 { 36 return x == pre[x] ? x : pre[x] = Find(pre[x]); 37 } 38 39 void Stpre(int n) 40 { 41 for(int i = 0; i <= n; i++) 42 pre[i] = i; 43 } 44 45 void Ststu() 46 { 47 memset(&pt,0,sizeof(Po)); 48 memset(&buy,0,sizeof(Bu)); 49 memset(&edge,0,sizeof(Ci)); 50 } 51 52 int Ojld(Point a, Point b) 53 { 54 int xx = a.x - b.x; 55 int yy = a.y - b.y; 56 return xx * xx + yy *yy; 57 } 58 59 int mycmp(City a, City b) 60 { 61 return a.w < b.w; 62 } 63 64 int ksu(int l)//K算法 65 { 66 int ans= 0; 67 for(int i = 1; i<= l; i++) 68 { 69 int fv = Find(edge[i].v); 70 int fu = Find(edge[i].u); 71 if(fu != fv) 72 { 73 pre[fu] = pre[fv]; 74 ans += edge[i].w; 75 } 76 } 77 return ans; 78 } 79 80 int main() 81 { 82 //freopen("input.txt","r",stdin); 83 int t; 84 cin >> t; 85 while(t--) 86 { 87 Ststu(); 88 int n, q; 89 scanf("%d%d",&n, &q); 90 for(int i = 1; i <= q; i++) 91 { 92 scanf("%d",&buy[i].m); 93 scanf("%d",&buy[i].ci); 94 for(int j = 1; j <= buy[i].m; j++) 95 scanf("%d",&buy[i].a[j]); 96 } 97 for(int i = 1; i <= n; i++) 98 scanf("%d%d",&pt[i].x, &pt[i].y); 99 int sum = 0; 100 for(int i = 1; i < n; i++) 101 { 102 for(int j = i + 1; j <= n; j++) 103 { 104 sum++; 105 edge[sum].u = i; 106 edge[sum].v = j; 107 edge[sum].w = Ojld(pt[i], pt[j]); 108 //printf("%d %d %d %d\n",sum,i,j,edge[sum].w); 109 } 110 } 111 sort(edge + 1, edge + sum + 1 , mycmp); 112 113 int ans = 0x7F7F7F7F; 114 for(int i = 0; i < (1 << q); i++) //二進(jìn)制枚舉 115 { 116 Stpre(n); 117 int temp = i; 118 int mst = 0; 119 for(int j = 1; j <= q; j++) 120 { 121 if(temp & 1) 122 { 123 mst += buy[j].ci; 124 for(int k = 2; k <= buy[j].m; k++) 125 { 126 int fx = Find ( buy[j].a[1] ); 127 int fy = Find( buy[j].a[k] ); 128 if(fy != fx) 129 pre[fy] = pre[fx]; 130 } 131 } 132 temp >>= 1; 133 } 134 mst += ksu(sum); 135 ans = min(ans, mst); 136 } 137 printf("%d\n",ans); 138 if(t)prln(""); 139 } 140 return 0; 141 }?
轉(zhuǎn)載于:https://www.cnblogs.com/Ash-ly/p/5397638.html
總結(jié)
以上是生活随笔為你收集整理的UVA 1151Buy or Build MST(最小生成树)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: HDU 2852 KiKi's K-Nu
- 下一篇: 【HNOI模拟By YMD】move