7-50 畅通工程之局部最小花费问题(35 分)
某地区经过对城镇交通状况的调查,得到现有城镇间快速道路的统计数据,并提出“畅通工程”的目标:使整个地区任何两个城镇间都可以实现快速交通(但不一定有直接的快速道路相连,只要互相间接通过快速路可达即可)。现得到城镇道路统计表,表中列出了任意两城镇间修建快速路的费用,以及该道路是否已经修通的状态。现请你编写程序,计算出全地区畅通需要的最低成本。
输入格式:
输入的第一行给出村庄数目N (1≤N≤100);随后的N(N−1)/2行对应村庄间道路的成本及修建状态:每行给出4个正整数,分别是两个村庄的编号(从1编号到N),此两村庄间道路的成本,以及修建状态 — 1表示已建,0表示未建。
输出格式:
输出全省畅通需要的最低成本。
输入样例:
4
1 2 1 1
1 3 4 0
1 4 1 1
2 3 3 0
2 4 2 1
3 4 5 0
输出样例:
3
思路:道路分为两种,一种是已经建立好了的,一种是没有建立的。采用克鲁斯卡尔算法,分为两遍处理,第一遍先把建立好的道路添加图中,只添加会影响连通性的,顺便统计添加了多少条。第二遍再跑一遍克鲁斯卡尔,将没有建好的道路按费用从小到大添加到图中。当添加了n-1条道路时,停止。
实质上是将克鲁斯卡尔分两遍跑。第一遍跑建好的道路,第二遍跑没建好的道路。
代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <vector>
#include <sstream>
#include <map>
#include <queue>
#include <stack>
#include <cstring>
#include <set>
#include <cmath>
#define INF 1000000
using namespace std;
int n;
struct edge
{
int x,y,cost,flag;
};
typedef struct edge edge;
edge a[5005];
int m;
int cmp(edge aa,edge bb)
{
return aa.cost<bb.cost;
}
int fa[105];
int Find(int x)
{
if(fa[x]==x) return x;
else return fa[x]=Find(fa[x]);
}
int main()
{
scanf("%d",&n);
m=n*(n-1)/2;
for(int i=0;i<m;i++)
{
scanf("%d%d%d%d",&a[i].x,&a[i].y,&a[i].cost,&a[i].flag);
}
sort(a,a+m,cmp);
for(int i=0;i<=n;i++)
{
fa[i]=i;
}
int cnt=0;
int ans=0;
for(int k=0;k<m;k++)
{
int x=a[k].x;
int y=a[k].y;
int flag=a[k].flag;
if(flag==1)
{
int aa=Find(x);
int bb=Find(y);
if(aa!=bb)
{
cnt++;
fa[aa]=bb;
if(cnt==n-1)
{
break;
}
}
}
}
if(cnt<n-1)
{
for(int k=0;k<m;k++)
{
int x=a[k].x;
int y=a[k].y;
int flag=a[k].flag;
int cost=a[k].cost;
if(flag==0)
{
int aa=Find(x);
int bb=Find(y);
if(aa!=bb)
{
cnt++;
ans+=cost;
fa[aa]=bb;
if(cnt==n-1)
{
break;
}
}
}
}
}
printf("%d\n",ans);
return 0;
}