题目描述
省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可)。现得到城镇道路统计表,表中列出了任意两城镇间修建道路的费用,以及该道路是否已经修通的状态。现请你编写程序,计算出全省畅通需要的最低成本。
输入描述:
测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( 1< N < 100 );随后的 N(N-1)/2 行对应村庄间道路的成本及修建状态,每行给4个正整数,分别是两个村庄的编号(从1编号到N),此两村庄间道路的成本,以及修建状态:1表示已建,0表示未建。
当N为0时输入结束。
输出描述:
每个测试用例的输出占一行,输出全省畅通需要的最低成本。
示例1
输入
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<stdio.h>
#include<math.h>
#include<algorithm>
#include<string.h>
#include<iostream>
#include<iomanip>
#include<vector>
#include<map>
#include<stack>
#include<queue>
using namespace std;
const int N = 5000;
int Tree[100];
//不需要修成一个圈,按最小代价生成树,一个点到各点之间都有通路。
typedef struct{
int start;
int end;
int cost;
int statue;
}Edge;
int findroot(int x){ //查找根节点
if(Tree[x] == -1){
return x;
}else{
return findroot(Tree[x]);
}
}
bool cmp(Edge e1,Edge e2){ //按修成,花费进行排序
if(e1.statue != e2.statue){
return e1.statue > e2.statue;
}else{
return e1.cost < e2.cost;
}
}
int main(){
int n;
Edge edge[N];
while(cin >> n){
for(int i = 1; i <= n; i++){ //初始化树节点
Tree[i] = -1;
}
for(int i = 0; i < n*(n-1)/2; i++){
cin >> edge[i].start >> edge[i].end >>edge[i].cost >>edge[i].statue;
}
sort(edge , edge+n*(n-1)/2 , cmp); //按花修成,费进行排序
int rst = 0;
for(int i = 0; i < n*(n-1)/2; i++){
int a = findroot(edge[i].start);
int b = findroot(edge[i].end);
if(a != b){
Tree[a] = b; //更新节点的子节点
if(edge[i].statue == 0){ //畅通中有没有修的,就加上花费。
rst += edge[i].cost;
}
}
}
cout << rst << endl;
}
return 0;
}