HDU1879 继续畅通工程 【图论】【最小生成树】【Kruskal】

xiaoxiao2021-02-28  76

【Problem Description】 省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可)。现得到城镇道路统计表,表中列出了任意两城镇间修建道路的费用,以及该道路是否已经修通的状态。现请你编写程序,计算出全省畅通需要的最低成本。 【Input】 测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( 1< N < 100 );随后的 N(N-1)/2 行对应村庄间道路的成本及修建状态,每行给4个正整数,分别是两个村庄的编号(从1编号到N),此两村庄间道路的成本,以及修建状态:1表示已建,0表示未建。 当N为0时输入结束。 【Output】 每个测试用例的输出占一行,输出全省畅通需要的最低成本。 【Sample Input】 3 1 2 1 0 1 3 2 0 2 3 4 0 3 1 2 1 0 1 3 2 0 2 3 4 1 3 1 2 1 0 1 3 2 1 2 3 4 1 0 【Sample Output】 3 1 0 【题解】 首先我们要知道这个“继续”是从哪来的: 畅通工程 这道题比上一道题多了一个“状态”的问题。因为有一些边是已经修了的,所以我们在Kruskal的时候希望优先选这些建好的边,这样就不用增加我的代价。因此我们要改的就是在前边排序的时候把修好的排在前面。 代码如下:

#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=100; const int M=N*(N-1)/2; int head[N+5],num,father[N+5]; int n,m; struct edge { int u,v,w,t; int next; edge(){next=-1;} }ed[4*M+5]; void build(int u,int v,int w,int t) { ed[++num].u=u; ed[num].v=v; ed[num].w=w; ed[num].t=t; ed[num].next=head[u]; head[u]=num; } int getfather(int a) { return father[a]==a?a:getfather(father[a]); } void unionn(int a,int b) { father[getfather(b)]=getfather(a); } bool cmp(edge a,edge b)//修好的放前边 { return a.t==b.t?a.w<b.w:a.t>b.t; } int kruskal() { int ans=0,tot=0; sort(ed+1,ed+1+num,cmp); for(int i=1;i<=n;i++) father[i]=i; for(int i=1;i<=num;i++) { if(getfather(ed[i].v)==getfather(ed[i].u))continue; unionn(ed[i].v,ed[i].u); ans+=ed[i].t?0:ed[i].w;//修了的不需要付出代价 if(++tot==n-1)return ans; } } int main() { while(scanf("%d",&n)&&n) { num=0; memset(head,-1,sizeof(head)); int m=n*(n-1)/2; for(int i=1;i<=m;i++) { int u,v,w,t; scanf("%d%d%d%d",&u,&v,&w,&t); build(u,v,w,t); build(v,u,w,t); } printf("%d\n",kruskal()); } return 0; }
转载请注明原文地址: https://www.6miu.com/read-96200.html

最新回复(0)