一、概述
给出一棵树(非二叉树),输出所有符合条件的路径。
当题目要求由根节点到叶节点的路径时,我们使用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);
}