[USACO08NOV]Cheering up the Cow Gc++
核心算法:Kruskal算法
題目中說:「刪去儘量多的邊」。就是指保留一棵最小生成樹。3d
構圖:code
咱們取一小段來分析一下:blog
(能夠把這個理解爲單位元)排序
按照題目中的意思,走過這一張的花費爲:get
C[1] + L + C[2] + L + C[1]it
即:C[1] + C[1] + 2L + C[2]io
走過這一張的花費爲:模板
C[1] + L(1,2) + C[2] + L(2,3) + C[3] + L(2,3) + C[2] + L(1,2) + C[1]
即:C[1] + (C[1] + 2L(1,2) + C[2]) + (C[2] + 2L(2,3) + C[3])
因此,咱們能夠推出:新的邊的權值,爲這條邊 起點權值+終點權值+兩倍邊權
而最後的結果,還要加上一開始起點權值。 (即取點權中的最小值,由於題目中要求最小)
代碼以下(細節見註釋):
#include <bits/stdc++.h> #define MAXN 1000000 #define INF 0x3f3f3f3f int fat[MAXN],siz[MAXN]; int c[MAXN],n,m,ans=0; struct EDGE{int from,to,val;} e[MAXN]; //鄰接矩陣 bool cmp(EDGE x,EDGE y){return x.val<y.val;} //比較器 按照邊的權值排序 int Find(int x) {return (fat[x]==x) ? x :fat[x]=Find(fat[x]);} void unionn (int x,int y) { x=Find(x); y=Find(y); if(siz[x]>siz[y]) std::swap(x,y); fat[x]=y; siz[y]+=siz[x]; } //並查集模板 bool kruskal() { int k=0; std::sort(e+1,e+m+1,cmp); for(int i=1;i<=m;++i) { if(k==n-1) break; if(Find(e[i].to)!=Find(e[i].from)) { unionn(e[i].to,e[i].from); ++k; ans+=e[i].val; } } return (k==n-1); } // kruskal模板 int main() { int minn=INF; std::scanf("%d%d",&n,&m); for(int i=1;i<=n;++i) {fat[i]=i; siz[i]=1;} //並查集初始化 for(int i=1;i<=n;++i) { std::scanf("%d",&c[i]); minn=std::min(minn,c[i]); //點權值中取最小值 } for(int i=1;i<=m;++i) { std::scanf("%d%d%d",&e[i].from,&e[i].to,&e[i].val); e[i].val=e[i].val*2+c[e[i].from]+c[e[i].to]; //從新定義權值 } if(kruskal()) std::printf("%d",ans+minn); return 0; }