7-1 畅通工程之局部最小花费问题(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
#include <iostream>
using namespace std;
//思路:先把原有的路合并为一个集合(不含回路),然后利用cruscal思想,把权值由小到大的路合并到集合里(不含回路),直到集合内点数等于总点数
//判断有没有回路只需判断两个点的祖先是不是相同,相同则不符
//坑题,数据上限是5000,所以数组要大
int father[10001];
int num[10001];
int num1=0;
typedef struct
{
int start;
int stop;
int fee;
int flag;
}road;
typedef struct
{
int note;
int no;
}hehe;
hehe hehe1[10001];
int tofind(int x)//找根
{
int temp=x;
while(father[temp]!=-1)
{
temp=father[temp];
}
return temp;
}
void tounion(int a,int b)//把b的根连到a的根上,合并成一个
{
int x=tofind(b);
father[tofind(b)]=tofind(a);
num[tofind(a)]+=num[x];
num1=num[tofind(a)];
}
road r[10001];
int main()
{
int n;
cin>>n;
if(n==1)
{
cout<<0;
return 0;
}
int i;
for(i=1;i<=n;i++)
{
father[i]=-1;
num[i]=1;
}//初始化,把每一个数的爸爸初始化为-1
for(i=0;i<(n*(n-1))/2;i++)
{
cin>>r[i].start>>r[i].stop>>r[i].fee>>r[i].flag;
if(r[i].flag==1)
{
if(tofind(r[i].start)==tofind(r[i].stop))
;
else
{
tounion(r[i].start,r[i].stop);
if(num1==n)
{
cout<<0;
return 0;
}
}
}
}
int tt=0;
int j;
for(i=0;i<n*(n-1)/2;i++)
{
if(r[i].flag==0)
{
hehe1[tt].no=r[i].fee;
hehe1[tt].note=i;
tt++;
}
}
for (i=1; i<tt; i++)
for(j=0; j<tt-i; j++)
{
if(hehe1[j].no>hehe1[j+1].no)
{
int t1,t2;
t1=hehe1[j].no;
hehe1[j].no=hehe1[j+1].no;
hehe1[j+1].no=t1;
t2=hehe1[j].note;
hehe1[j].note=hehe1[j+1].note;
hehe1[j+1].note=t2;
}
}//把权值由小到大排序
int sum=0;
for(i=0;i<tt;i++)
{
int temp=hehe1[i].note;
if(tofind(r[temp].start)==tofind(r[temp].stop))
continue;
else
{
sum+=hehe1[i].no;
tounion(r[temp].start,r[temp].stop);
if(num1==n)
{
cout<<sum;
break;
}
}
}
}