[bzoj1601]灌水_kruskal
阿新 • • 發佈:2018-03-20
scan n) 條件 sca += 如果 font == cin
灌水 bzoj-1601
題目大意:給你n塊地,將兩塊地之間連通有代價$P_{i,j}$,單獨在一塊地打井需要代價$C_i$,問將所有的井都有水的代價是多少。
註釋:1<=n<=300.
想法:這種題做過一遍就好了,我們新建立一個0號節點。如果兩塊地之間打通就在這兩個點之間連邊。如果這個點單獨打井就將這個點與新建節點連邊,權值為打井代價。然後跑最小生成樹。首先我們知道,這n塊地中至少有一塊地是打井的,不然就算所有的點都連通,也是沒有水的。所以,這個強大的算法顯然是正確的。
最後,附上醜陋的代碼... ...
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; struct Node { int a,b,val; }f[1001000]; int fa[10001]; bool cmp(Node a,Node b) { return a.val<b.val; } int find(int x) { return x==fa[x]?x:(fa[x]=find(fa[x])); } bool merge(int x,int y) { x=find(x);y=find(y); if(x==y) return false; fa[x]=y;return true; } int main() { int n; scanf("%d",&n); int cnt=0; for(int i=0;i<=n;i++) fa[i]=i; for(int i=1;i<=n;i++)//向0號節點加邊 { int x; scanf("%d",&x); f[++cnt].a=0; f[cnt].b=i; f[cnt].val=x; } for(int i=1;i<=n;i++)//鄰接矩陣,地與地之間的聯通代價 { for(int j=1;j<=n;j++) { int x; cin >> x; if(i>j) { f[++cnt].a=i; f[cnt].b=j; f[cnt].val=x; } } } sort(f+1,f+cnt+1,cmp); int count=0; int ans=0; for(int i=1;i<=cnt;i++)//kruskal { if(merge(f[i].a,f[i].b)) { ans+=f[i].val; count++; } if(count==n) break;//註意,我們是在跑n+1個點的kruskal,所以count的退出條件是count==n } printf("%d\n",ans); return 0; }
小結:思路題,超級好玩的qwq
[bzoj1601]灌水_kruskal