城市建设(建图 + 最小生成树)

栋栋居住在一个繁华的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
相关文章
相关标签/搜索