紀中暑假集訓 2020.08.08【NOIP提高組】模擬 T2:【Usaco2008 Oct 資格賽】灌水
阿新 • • 發佈:2020-08-08
【Usaco2008 Oct 資格賽】灌水
Description
Farmer John已經決定把水灌到他的n(1<=n<=300)塊農田,農田被數字1到n標記。把一塊土地進行灌水有兩種方法,從其他農田飲水,或者這塊土地建造水庫。
建造一個水庫需要花費wi(1<=wi<=100000),連線兩塊土地需要花費Pij(1<=pij<=100000,pij=pji,pii=0).
計算Farmer John所需的最少代價。
Input
第一行:一個數n
第二行到第n+1行:第i+1行含有一個數wi
第n+2行到第2n+1行:第n+1+i行有n個被空格分開的數,第j個數代表pij。
Output
第一行:一個單獨的數代表最小代價.
Sample Input
4
5
4
4
3
0 2 2 2
2 0 3 3
2 3 0 4
2 3 4 0
Sample Output
9
輸出詳解:
Farmer John在第四塊土地上建立水庫,然後把其他的都連向那一個,這樣就要花費3+2+2+2=9
反思&題解
比賽&正解思路: (我是絕對不會告訴你我之前做過這道題……) 模型很顯然是一個最小生成樹,將每個點與一個0號節點連一個邊,邊權是建造水庫的的價格,跑一邊最小生成樹就過了
反思: 做過的題不切就不對了吧
CODE
#include<bits/stdc++.h> using namespace std; struct arr { int u,v,w; }a[500005]; int n,tot,num,ans,fa[305]; bool cmp(arr x,arr y) { return x.w<y.w; } int find(int k) { if (fa[k]==k) return k; else { fa[k]=find(fa[k]); return fa[k]; } } int main() { scanf("%d",&n); int i; for (i=1;i<=n;i++) { int x; scanf("%d",&x); a[++tot].u=0; a[tot].v=i; a[tot].w=x; a[++tot].u=i; a[tot].v=0; a[tot].w=x; } for (i=1;i<=n;i++) { int j; for (j=1;j<=n;j++) { int x; scanf("%d",&x); if (i!=j) { a[++tot].u=i; a[tot].v=j; a[tot].w=x; } } } for (i=0;i<=n;i++) fa[i]=i; sort(a+1,a+1+tot,cmp); for (i=1;i<=tot;i++) { int t1=find(a[i].u),t2=find(a[i].v); if (t1!=t2) { num++; ans+=a[i].w; fa[t1]=t2; if (num==n) break; } } printf("%d\n",ans); return 0; }