問題描述
棟棟居住在一個繁華的C市中,然而,這個城市的道路大都年久失修。市長準備重新修一些路以方便市民,於是找到了棟棟,希望棟棟能幫助他。
C市中有n個比較重要的地點,市長希望這些地點重點被考慮。現在可以修一些道路來連接其中的一些地點,每條道路可以連接其中的兩個地點。另外由於C市有一條河從中穿過,也可以在其中的一些地點建設碼頭,所有建了碼頭的地點可以通過河道連接。
棟棟拿到了允許建設的道路的信息,包括每條可以建設的道路的花費,以及哪些地點可以建設碼頭和建設碼頭的花費。
市長希望棟棟給出一個方案,使得任意兩個地點能只通過新修的路或者河道互達,同時花費盡量小。
輸入格式
輸入的第一行包含兩個整數n, m,分別表示C市中重要地點的個數和可以建設的道路條數。所有地點從1到n依次編號。
接下來m行,每行三個整數a, b, c,表示可以建設一條從地點a到地點b的道路,花費爲c。若c爲正,表示建設是花錢的,如果c爲負,則表示建設了道路後還可以賺錢(比如建設收費道路)。
接下來一行,包含n個整數w_1, w_2, …, w_n。如果w_i爲正數,則表示在地點i建設碼頭的花費,如果w_i爲-1,則表示地點i無法建設碼頭。
輸入保證至少存在一個方法使得任意兩個地點能只通過新修的路或者河道互達。
輸出格式
輸出一行,包含一個整數,表示使得所有地點通過新修道路或者碼頭連接的最小花費。如果滿足條件的情況下還能賺錢,那麼你應該輸出一個負數。
樣例輸入
5 5
1 2 4
1 3 -1
2 3 3
2 4 5
4 5 10
-1 10 10 1 1
樣例輸出
9
具體思路可以參考博客:藍橋杯 城市建設(kruscal變形)
這裏給大家列舉幾個小坑:兩遍kruscal記得都先進行初始化,node結構體數組要開大一點。
做完也有兩個比較簡單的kruscal和並查集的題可以去鞏固一下:HOJ1232並查集,HOJ1863暢通工程Kruscal,隔壁兩篇博客也有這兩個的ac代碼。
#include <algorithm>
#include <cstring>
#include <iostream>
#include <cstdio>
using namespace std;
struct Node{
int a;
int b;
int cost;
};
Node node[200005];
int par[10010];
void init(int n){
for(int i = 0;i <= n;i++){
par[i] = i;
}
}
int cmp(const Node& a,const Node& b){
return a.cost < b.cost;
}
int find(int x){
if(x == par[x]) return x;
return par[x] = find(par[x]);
}
int kruscal(int n,int m){
init(n);
sort(node,node+m,cmp);
int num = 0,sum = 0;
for(int i = 0;i < m;i++){
int fx = find(node[i].a);
int fy = find(node[i].b);
int cst = node[i].cost;
if(fx != fy || cst < 0){
sum += cst;
if(fx != fy){
par[fx] = fy;
num++;
}
}
}
if(num < n - 1) sum = -1;
return sum;
}
int main(){
int n,m;
scanf("%d %d",&n,&m);
for(int i = 0;i < m;i++){
scanf("%d %d %d",&node[i].a,&node[i].b,&node[i].cost);
}
int allcost1 = kruscal(n,m);
for(int i = 1;i <= n;i++){
scanf("%d",&node[m].cost);
if(node[m].cost != -1){
node[m].a = 0;
node[m].b = i;
m++;
}
}
int allcost2 = kruscal(n+1,m);
if(allcost1 == -1){
cout<<allcost2<<endl;
}
else{
int res = min(allcost1,allcost2);
cout<<res<<endl;
}
return 0;
}