Description
省政府“畅通工程”的目标是使全省的任何两个村庄之间都可以实现公路交通(不一定有直接的公路相连,只要能间接通过公路可达即可)。现得到城镇道路统计表,表中列出了任意两城镇之间修建道路的费用,以及该道路是否已经修通的状态。现请你编写程序,计算出全省畅通需要的最低成本。
Input
测试输出包含若干个测试用例。每个测试用例的第一行给出村庄数目N(1≤N≤100);随后的N(N−1)/2行对应村庄间道路的成本及修建状态:每行给出4个正整数,分别是两个村庄的编号(从1编号到N),此两村庄间道路的成本,以及修建状态— 1表示已建,0表示未建。
Output
每个测试用例的输出占一行,输出全省畅通需要的最低成本。
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
#include <iostream>
#include<vector>
#include<algorithm>
using namespace std;
int n;//村庄数
int m;//村庄间的路的总数
struct Edge {
int u; //边的起始顶点
int v; //边的终止顶点
int w; //边的权值
bool operator<(const Edge& e) const {
return w < e.w; //用于按w递增排序
}
}; //边集
Edge E[50 * 99];
typedef struct node {
int rank; //结点对应秩,当前结点到叶节点的个数
int parent; //结点对应双亲下标
}UFSTree; //并查集树的结点类型
UFSTree t[50];
int FIND_SET(int x) { //在x所在子树中查找根的编号
if (x != t[x].parent)
return(FIND_SET(t[x].parent));
else
return(x);
}
void UNION(int x, int y) {//合并两颗生成树为一颗
if (t[x].rank > t[y].rank)
t[y].parent = x;
else {
t[x].parent = y;
if (t[x].rank == t[y].rank)
t[y].rank++;
}
}
//用于按w递增排序
//bool cmp(Edge a, Edge b) {
// return a.v < b.v;
//}
void Kruskal() {
int sum = 0;//路的修建成本
sort(E, E + m);//按照路的修建成本从低到高排序
for (int i = 1; i <= n; i++) {//初始化t
t[i].rank = 0;
t[i].parent = i;
}
int k = 1;
int j = 0;
int ul, vl, sn1, sn2;
while (k < n) {
ul = E[j].u;
vl = E[j].v;
sn1 = FIND_SET(ul);
sn2 = FIND_SET(vl);
if (sn1 != sn2) {
k++;
sum += E[j].w;
UNION(sn1, sn2);
}
j++;
}
cout << sum << endl;
}
int main()
{
while (cin >> n) {
if (n == 0)break;
m = n * (n - 1) * 0.5;
int a, b, v, t;
for (int i = 0; i < n * (n - 1) / 2; i++) {
cin >> a >> b >> v >> t;
E[i] = { a,b,v };
if (t == 1) E[i].w = 0;//已修建
}
Kruskal();
}
}