北大 2012 Jungle Roads

题目:
输入边的两端点和边值,求最小生成树(最小支撑树)的值。

 

思路:

 

过程:
本题调试问题出在如下几处:
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;
}

  

转载于:https://www.cnblogs.com/songshu-gancuimian/p/6649799.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值