洛谷 P1364医院设置 C语言题解

只是一道在一棵树上选取一个节点作为重心,然后求得周围节点到重心的加权距离最小的题目,如果用一般的树结构来存储的话,因为要同时寻找某个节点的儿子节点和父亲节点,所以会涉及到双向的树。

为了将题目简化,我们用邻接表来储存这棵树,邻接表中的元素分别储存树的权值,左右孩子(如果没有,就是0,有的话就是对应节点的编号),父亲节点(如果没有,就是0,有的话就是对应节点的编号),用二维数组来表示邻接矩阵。

对于邻接矩阵的每一个节点进行广度优先搜索,bfs,在每次计算的时候还要将目前访问的节点与重心的相对距离传入函数,完成计算。计算完所有节点的值之后,从这中间找到最小的输出。

想到将这道题用邻接表处理之后,编程过程并不复杂。

map是邻接表,flag是确定当前节点是否被访问过的数组,total储存着每个节点计算的值,min是最小数的阈值(设置一个不可能的答案),在for循环中将树中的信息储存起来,re_flag函数将flag数组清零,

在for循环中对每一个节点进行bfs,将结果result(全局变量)存入total数组中,最后进行比较,输出最小值即可。

int main()
{
	int map[150][6] = {0};
	int n;
	int flag[n + 1] ;
	int total[n + 1];
	int min = 1000000;
	scanf("%d",&n);
	for(int i = 1;i <= n;i++)
	{
		int value,L_child,R_child;
		scanf("%d%d%d",&value,&L_child,&R_child);
		map[i][0] = value;
		map[i][1] = L_child;
		map[i][2] = R_child;
		//将左右孩子与父亲节点建立联系 
		map[L_child][3] = i;
		map[R_child][3] = i;
	}
	re_flag(flag,n);
	for(int i = 1;i <= n;i++)
	{
		bfs(map,i,flag,1);
		total[i] = result;
		re_flag(flag,n);
		min = (min < result) ? min : result;
		result = 0;
		
	}
	printf("%d",min);
	return 0;
 } 

核心的代码是bfs,参数分别是邻接表,开始节点的编号,flag数组,节点权值应该乘的倍数num。
先将当前节点的flag值设为1,再分别对其左右孩子,父亲节点进行bfs,如果其节点符合要求,就在从这个节点开始进行bfs。在进行下一次递归时,应为相对位置的增加,num应该递增。
同时将该节点的flag值设为1表示已经被访问过。最后得到的result的值就是以这个节点位重心所得的计算结果。

void bfs(int map[][6],int s_node,int flag[],int num)
{

	flag[s_node] = 1;
	if(map[s_node][1] != 0&&flag[map[s_node][1]] == 0)//左孩子且没有被访问过 
	{
		int loc = map[s_node][1];
		result += num * map[loc][0];
		flag[loc] = 1;
		//printf("num = %d result = %d value = %d\n",num,result,map[loc][0]);
		bfs(map,loc,flag,num + 1);
	}
	if(map[s_node][2] != 0&&flag[map[s_node][2]] == 0)//右孩子 
	{
		int loc = map[s_node][2];
		result += num * map[loc][0];
		flag[loc] = 1;
		//printf("num = %d result = %d value = %d\n",num,result,map[loc][0]);
		bfs(map,loc,flag,num + 1);		
	}
	if(map[s_node][3] != 0&&flag[map[s_node][3]] == 0)//父亲节点 
	{
		int loc = map[s_node][3];
		result += num * map[loc][0];
		flag[loc] = 1;
		//printf("num = %d result = %d value = %d\n",num,result,map[loc][0]);
		bfs(map,loc,flag,num + 1);		
	}
}

这个代码还有很大的改进空间,这里只是说明基本思想,

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值