题目一:
HDOJ 1879
网址:http://acm.hdu.edu.cn/showproblem.php?pid=1879
问题描述
省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可)。现得到城镇道路统计表,表中列出了任意两城镇间修建道路的费用,以及该道路是否已经修通的状态。现请你编写程序,计算出全省畅通需要的最低成本。
输入
测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( 1< N < 100 );随后的 N(N-1)/2 行对应村庄间道路的成本及修建状态,每行给4个正整数,分别是两个村庄的编号(从1编号到N),此两村庄间道路的成本,以及修建状态:1表示已建,0表示未建。
当N为0时输入结束。
输出
每个测试用例的输出占一行,输出全省畅通需要的最低成本。
示例输入
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
示例输出
3 1 0
解题思路:
最小生成树问题可以用kruskal算法解。node结构体记录所有可以连通的边的两个端点和边的权重。将所有的边按照权重的大小进行从小到大排序,只要一个边的两个端点不在同一个集合内(避免成环),就将该边的权重加到sum上,当已经加上的边的个数等于n-1(n为点的个数)时最小生成树就产生了(树中边数等于点的个数减一)。(已经连通的两个点所在的边的权重设置为0)
*输入时用scanf进行输入
程序:
#include<iostream>
#include<algorithm>
#include<cstdio>
usingnamespace std;
constint MAX =10001;
int* p, row, num; //num表示点的个数,row表示输入的行数
void set(intn)
{
for(int i = 0; i <= n; i++)
p[i] = i;
}
structnode
{
int from;
int to;
int value;
}N[MAX];
int Find(intx)
{
if(x == p[x])
returnx;
else
return p[x] = Find(p[x]); //路径压缩
}
//判断两个村庄是否相通,不相通返回true,否则返回false
bool Merge(intp1, intp2)
{
p1 = Find(p1), p2 = Find(p2);
if(p1 != p2)
{
p[p1] = p2;
returntrue;
}
returnfalse;
}
//定义sort比较的规则
bool cmp(nodea, nodeb)
{
returna.value < b.value;
}
//最小生成树算法
void kruskal()
{
sort(N, N + row, cmp);
int sum =0, count = 0;
for(int i = 0; i < row; i++)
{
if(Merge(p[N[i].from],p[N[i].to]))
{
sum += N[i].value;
count++;
}
if(count== num - 1) //边数等于点的个数减一
break;
}
cout << sum << endl;
}
int main()
{
int n;
while(scanf("%d",&n) && n)
{
p = newint[n+1];
set(n);
num = n;
row = (n * (n-1)) / 2;
for(int i = 0; i < row; i++)
{
int d;
scanf("%d%d%d%d",&N[i].from,&N[i].to,&N[i].value,&d);
if(d == 1)
N[i].value = 0; //已经连通的排在最前面且边的权重为0
}
kruskal();
delete[] p;
}
return 0;
}