原文地址: http://moilk.org/blog/2016/09/05/ccf2014124/
問題描述
雷雷承包了很多片麥田,爲了灌溉這些麥田,雷雷在第一個麥田挖了一口很深的水井,所有的麥田都從這口井來引水灌溉。
爲了灌溉,雷雷需要建立一些水渠,以連接水井和麥田,雷雷也可以利用部分麥田作爲“中轉站”,利用水渠連接不同的麥田,這樣只要一片麥田能被灌溉,則與其連接的麥田也能被灌溉。
現在雷雷知道哪些麥田之間可以建設水渠和建設每個水渠所需要的費用(注意不是所有麥田之間都可以建立水渠)。請問灌溉所有麥田最少需要多少費用來修建水渠。
輸入格式
輸入的第一行包含兩個正整數n, m,分別表示麥田的片數和雷雷可以建立的水渠的數量。麥田使用1, 2, 3, ……依次標號。
接下來m行,每行包含三個整數ai, bi, ci,表示第ai片麥田與第bi片麥田之間可以建立一條水渠,所需要的費用爲ci。
輸出格式
輸出一行,包含一個整數,表示灌溉所有麥田所需要的最小費用。
樣例輸入
4 4
1 2 1
2 3 4
2 4 2
3 4 3
樣例輸出
6
樣例說明
建立以下三條水渠:麥田1與麥田2、麥田2與麥田4、麥田4與麥田3。
評測用例規模與約定
前20%的評測用例滿足:n≤5。
前40%的評測用例滿足:n≤20。
前60%的評測用例滿足:n≤100。
所有評測用例都滿足:1≤n≤1000,1≤m≤100,000,1≤ci≤10,000。
解題說明
這是一個無向圖的最小生成樹問題,以下爲採用kruskal算法的解決方案。
// kruskal最小生成樹算法
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
struct Edge{
int x,y,value;
Edge(int xx=0,int yy=0,int v=0){
x=xx,y=yy,value=v;
}
};
int n,m;
int id[1001];
int sz[1001]={1};
vector<Edge> edges;
bool cmp(Edge a,Edge b){
return (a.value<b.value);
}
int _find(int p){
if(p==id[p]) return p;
return id[p]=_find(id[p]); // 路徑壓縮
}
bool _union(int x,int y){
x=_find(x);
y=_find(y);
if(x==y){
return false;
}
if(sz[x]<sz[y]){ // 小樹接大樹
id[x]=y;
sz[y]+=sz[x];
}else{
id[y]=x;
sz[x]+=sz[y];
}
return true;
}
int kruskal(){
int res=0,count=0;
for(int i=0;i<m;i++){
if(_union(edges[i].x,edges[i].y)){
res+=edges[i].value;
count++;
if(count==n-1){
break;
}
}
}
return res;
}
int main(void){
cin>>n>>m;
int x,y,v;
for(int i=0;i<m;i++){
cin>>x>>y>>v;
edges.push_back(Edge(x,y,v));
}
for(int i=0;i<=n;i++){
id[i]=i;
}
sort(edges.begin(),edges.end(),cmp);
cout<<kruskal()<<endl;
return 0;
}