题目:
输入边的两端点和边值,求最小生成树(最小支撑树)的值。
思路:
过程:
本题调试问题出在如下几处:
1.用%c会读入回车符(用getchar()有的平台又会出问题),所以以后读字符都直接用%s,然后在取字符串第一个字符即可。
char c[4];
scanf("%s",c);
printf("%c",c[0]);
2.边排序后遍历所有边,我犯了个错(以为只要所有点都出现过,那后面的边就不用遍历了),忘记了即使所有点都出现过,
也可能分散在多个连通分量内,所以最小支撑树不一定已生成。最保险的方式还是把所有边,一个个全遍历完。
3.本题测试用例不太符合题目要求,既有A 1 A 24这种自环边,也有D 2 A 45 C 5这种(ASCII大的后面跟小的),重复的A 2 B 44 B 100.
代码:
#include <iostream>
#include <stdio.h>
#include <cstring>
#include <algorithm>
using namespace std;
//边结构体
struct Edge{
char Node1; //边的两点
char Node2;
int value; //边值
};
//相关变量和函数
Edge edge[77]; //边数组
int inputNum; //输入边的个数
int joinMark[26]; //A-Z是否参与,0:没参加;1:参加
char storeTree[26]; //并查集,存树
char find(char c){ //查找结点c的根
char cc=c;
while(storeTree[cc-65]!=cc){
cc=storeTree[cc-65];
}
return cc;
}
bool cmp(Edge e1,Edge e2){ //边值大小比较函数
if(e1.value<=e2.value)
return true;
return false;
}
//主函数
int main(){
int n,n2,i,sum; //n:参与点的个数,n2:n的备份,sum:支撑树的边和
char node1[5],node2[5]; //边的两点
int k,cost; //k:每行输入k个边;cost:边的值
while(scanf("%d",&n)!=EOF && n){ //输入n(n=0时退出)
//memset(edge,0,77*sizeof(Edge)); //初始化变量值
inputNum=0;
memset(joinMark,0,26*sizeof(int));
for(i=0;i<26;i++)
storeTree[i]=char(i+65);
sum=0;
n2=n; //边的输入
while(--n2){ //n-1行输入
scanf("%s %d",node1,&k);
while(k--){ //每行k个边
scanf("%s %d",node2,&cost);
edge[inputNum].Node1=node1[0];
edge[inputNum].Node2=node2[0];
edge[inputNum].value=cost;
inputNum++;
}
}
sort(edge,edge+inputNum,cmp); //把边按值从小到大的顺序排列
i=0;
while(i<inputNum){ //找最小支撑树
//边的两点都未参加
if(joinMark[edge[i].Node1-65]==0 && joinMark[edge[i].Node2-65]==0){
if(edge[i].Node1==edge[i].Node2){ //自己指向自己的边不算
i++;
continue;
}
if(edge[i].Node1<edge[i].Node2) //ASCII码小的为父结点
storeTree[edge[i].Node2-65]=edge[i].Node1;
else
storeTree[edge[i].Node1-65]=edge[i].Node2;
//边的两点都参加
joinMark[edge[i].Node1-65]=joinMark[edge[i].Node2-65]=1;
sum+=edge[i].value; //边值加入sum
}
else{ //至少一点已参加
//两点都已参加
if(joinMark[edge[i].Node1-65]==1 && joinMark[edge[i].Node2-65]==1){
if(edge[i].Node1==edge[i].Node2){ //自己指向自己的边跳过
i++;
continue;
}
char root1,root2; //两点属于不同连通量
if((root1=find(edge[i].Node1))!=(root2=find(edge[i].Node2))){
if(root1<root2){ //哪个根的ASCII码小,则为父结点
storeTree[root2-65]=root1;
sum+=edge[i].value;
}
else{
storeTree[root1-65]=root2;
sum+=edge[i].value;
}
}
}
else{ //只一个点已参加
if(joinMark[edge[i].Node1-65]==1){ //已参加的点为父结点
storeTree[edge[i].Node2-65]=edge[i].Node1;
joinMark[edge[i].Node2-65]=1;
}
else{
storeTree[edge[i].Node1-65]=edge[i].Node2;
joinMark[edge[i].Node1-65]=1;
}
sum+=edge[i].value; //边值加入sum
}
}
i++; //跳到下一边
}
printf("%d\n",sum); //输出结果
}
return 0;
}