PAT (Advanced Level) Practice 1053 Path of Equal Weight 普通树的DFS及路径保存

一、概述

给出一棵树(非二叉树),输出所有符合条件的路径。

当题目要求由根节点到叶节点的路径时,我们使用DFS实现。

二、分析

因为是普通的树,因此每个节点的孩子节点数量未知,需要使用vector来记录,结构体如图:

struct node
{
	long long int weight;
	vector<int> child;
}node[100];

然后输入权值和节点之间的关系。

int N, M;
scanf("%d %d", &N, &M);
scanf("%lld", &S);
int i;
for (i = 0; i<N; i++)
	scanf("%lld", &node[i].weight);
for (i = 0; i<M; i++)
{
    int num;
	scanf("%d", &num);
	int childnum;
	scanf("%d", &childnum);
	int j;
	for (j = 0; j<childnum; j++)
	{
		//scanf("%d",&(node[num].child[j]));
		int child;
    	scanf("%d", &child);
		node[num].child.push_back(child);
	}
	//sort(node[num].child[0], node[num].child[childnum], cmp);
    //sort(node[num].child, node[num].child+childnum, cmp);
	sort(node[num].child.begin(), node[num].child.end(), cmp);
}

记录数据时有以下几点要注意:

首先,树使用结构体数组来保存,每个节点的孩子用下标来指代。

其次,对于vector,scanf不能直接调用&vector,要先用变量保存输入值,然后用vector的push_back函数将变量push到尾部。

然后,由于输出要按节点权重由大到小,那么需要孩子节点有序,即,将每个结构体中的vector排序,这里很容易写错,我把两个写错的都注释掉了,简而言之,sort按如下形式

sort(vector.begin(),vector.end(),cmp)

sort的变量需要是指针,而不能是值,因此要用begin(),同时注意括号。

对于cmp函数,变量直接用int即可,即vector的元素类型,注意vector存的是下标,那么cmp中输入的也是下标,比较的就应该是node[a].weight>node[b].weight;

而不能是

a>b;

这里也容易弄晕。

注意这里写错了报错都是新出来一个文件,说那里面有错误,如果不知道那就很难找出来。

最后DFS即可,如下:

void DFS(int root, long long int tempSum, int pathNum)
{
	if (node[root].child.empty())
		if (tempSum +node[root].weight!= S)
			return;
		else
		{
			path[pathNum] = node[root].weight;
			int i;
			if(numenter==0)
			;
			else
			{
				printf("\n");
			}
			numenter++;
			for (i = 0; i<pathNum; i++)
				printf("%lld ", path[i]);
			printf("%lld", path[i]);
			return;
		}
	else
	{
		if (tempSum+node[root].weight >= S)
			return;
	}
	path[pathNum] = node[root].weight;
	int childnum = node[root].child.size();
	int j;
	for (j = 0; j<childnum; j++)
		DFS(node[root].child[j], tempSum + node[root].weight, pathNum + 1);
}

我们知道DFS中要使用一些全局变量的,在这里最明显的就是记录路径的数组path。

按照规则,DFS首先要写出递归出口:

叶节点返回:如果权值和符合规则则输出path中的值;

非叶节点,如果权值大于S那么返回;

然后开始处理,更新path数组,既然没有从出口出去说明该节点是路径上的一个,那么要把节点下标保存;

最后开始递归即可:

因为是普通的树,所以递归要进行该节点的孩子的数量的次数,DFS的参数也有讲究,注意更新tempSum和pathNum。

我们已经知道,DFS的第一个参数与后面的参数在逻辑上是分开的,即我们如果想要考虑当前DFS所处理的节点的影响,要另外更新tempSum和path数组,再然后再判断。其实这个debug一次就好。关键是学会在DFS期间保存路径。

三、总结

学习普通的树的节点的保存方式和输入方式,最重要的是掌握DFS期间进行路径保存的方法。

PS:代码如下:

#include<stdio.h>
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
struct node
{
	long long int weight;
	vector<int> child;
}node[100];
bool cmp(int a, int b)
{
	return node[a].weight>node[b].weight;
}
long long int path[100];
long long int S;
int numenter=0; 
void DFS(int root, long long int tempSum, int pathNum)
{
	if (node[root].child.empty())
		if (tempSum +node[root].weight!= S)
			return;
		else
		{
			path[pathNum] = node[root].weight;
			int i;
			if(numenter==0)
			;
			else
			{
				printf("\n");
			}
			numenter++;
			for (i = 0; i<pathNum; i++)
				printf("%lld ", path[i]);
			printf("%lld", path[i]);
			return;
		}
	else
	{
		if (tempSum+node[root].weight >= S)
			return;
	}
	path[pathNum] = node[root].weight;
	int childnum = node[root].child.size();
	int j;
	for (j = 0; j<childnum; j++)
		DFS(node[root].child[j], tempSum + node[root].weight, pathNum + 1);
}
int main()
{
	int N, M;
	scanf("%d %d", &N, &M);
	scanf("%lld", &S);
	int i;
	for (i = 0; i<N; i++)
		scanf("%lld", &node[i].weight);
	for (i = 0; i<M; i++)
	{
		int num;
		scanf("%d", &num);
		int childnum;
		scanf("%d", &childnum);
		int j;
		for (j = 0; j<childnum; j++)
		{
			//scanf("%d",&(node[num].child[j]));
			int child;
			scanf("%d", &child);
			node[num].child.push_back(child);
		}
		//sort(node[num].child[0], node[num].child[childnum], cmp);
		//sort(node[num].child, node[num].child+childnum, cmp);
		sort(node[num].child.begin(), node[num].child.end(), cmp);
	}
	DFS(0, 0, 0);
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值