城市建設(建圖 + 最小生成樹)

棟棟居住在一個繁華的C市中,然而,這個城市的道路大都年久失修。市長準備從新修一些路以方便市民,因而找到了棟棟,但願棟棟能幫助他。 

C市中有n個比較重要的地點,市長但願這些地點重點被考慮。如今能夠修一些道路來鏈接其中的一些地點,每條道路能夠鏈接其中的兩個地點。另外因爲C市有一條河從中穿過,也能夠在其中的一些地點建設碼頭,全部建了碼頭的地點能夠經過河道鏈接。 

棟棟拿到了容許建設的道路的信息,包括每條能夠建設的道路的花費,以及哪些地點能夠建設碼頭和建設碼頭的花費。 

市長但願棟棟給出一個方案,使得任意兩個地點能只經過新修的路或者河道互達,同時花費盡可能小。 

樣例說明 
建設第二、三、4條道路,在地點四、5建設碼頭,總的花費爲9。 
數據規模和約定 
對於100%的數據,1  < =  n  < =  10000,1  < =  m  < =  100000,-1000< =c< =1000,-1< =w_i< =1000,w_i≠0。 

輸入
輸入的第一行包含兩個整數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

最早的思路也是創建最小生成樹 ,運用並查集的思路在鏈接兩個並查集的時候判斷是否用碼頭更加好 。卡在90%,多是哪裏打錯了 , 而後看到大神的作法 , 虛擬出一個點0 , 而後鏈接每一個n點 , 邊權爲碼頭的費用 , 而後跑一邊最小生成樹。。
太優秀了,在注意一下若是隻用到虛擬的點邊只有一條的話 , 就不用加上這個費用;
#include<bits/stdc++.h>
using namespace std ; struct no { int u,v,w; }eg[200001]; int fa[100001],val[100001]; bool cmp(no a , no b) { return a.w<b.w; } int find(int u) { if(fa[u]==u)return u; return fa[u]=find(fa[u]); } int main() { int n,m; scanf("%d%d",&n,&m); for(int i=1 ; i<=m ; i++) { int a,b,c; scanf("%d%d%d",&eg[i].u , &eg[i].v , &eg[i].w); } for(int i=1 ; i<=n ; i++) { scanf("%d",&val[i]); if(val[i]!=-1) { eg[++m].u=0; eg[m].v=i; eg[m].w=val[i]; } } for(int i=1 ; i<=n ; i++) fa[i]=i; sort(eg+1,eg+1+m,cmp); int ans=0,W=0,IDcost; for(int i=1 ; i<=m ; i++) { int u=eg[i].u , v=eg[i].v , w=eg[i].w; int x=find(u) , y=find(v); if((x!=y) || w<0) { fa[x]=y; ans+=w; if(u==0) { W++; IDcost=w; } } } if(W==1)///只是建一個碼頭是
    ans-=IDcost; printf("%d\n",ans); }
View Code
相關文章
相關標籤/搜索