一、题目详情
输入解释
- 第一行给出三个数字N、M、S,分别为树的结点数量、树的非叶节点数量、给定的权重
- 第二行给出N个数字,分别是编号1~N的结点的权重
- 接下来M行依次为:非叶节点的编号 该结点的子结点个数 子结点的编号
输出解释
每行输出一个路径(以结点的权重表示),使得路径上的结点权重相加之和等于给定的权重
思路
- 首先是确定数据结构,考虑静态实现,邻接表可以用vector<int> child来实现。每个结点都有一个权重,所以考虑用结构体node来表示结点。node中有一个int weight和vector<int> child。nodes[maxn]为结构体数组。
- 可以想到是用DFS来做,需要传递的参数有:当前路径上的结点个数num(如果是用数组来表示路径的话,必须要有结点个数,不然给数组中的哪个元素赋值呢)、当前的边权之和w、当前正在处理的结点index(有了这个才能通过child数组找到孩子哇)、保存路径的数组path[]设置为全局变量(不知道为什么,DFS都是这样做的)
- 递归式:DFS(nodes[index].child[i],num+1,w+nodes[nodes[index].child[i]].weight)
- 递归边界:有两个需要注意的条件 ①sum和S的大小关系(sum小于S时,继续递归,sum大于S时,没有可行的解,回溯) ②题目要求路径必须是从根节点到叶节点,因此要判断是否为叶节点,在这个题中就是在sum等于S时判断nodes[index].child.size()是否为0。
- 题目要求在有多条路径时,要先输出结点权重大的,可以对child进行排序,这样dfs时就是按权重从大到小进行的。
二、实现代码
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn = 111;
int N,M,S;
int path[maxn];
struct node
{
int weight;
vector <int> child;
}nodes[maxn];
bool cmp(int a,int b)
{
return nodes[a].weight>nodes[b].weight;
}
void DFS(int index,int num,int sum)
{
if(sum>S) return;
else if(sum==S){
if(nodes[index].child.size()==0)
{
for(int i=0;i<num;i++)
{
printf("%d",nodes[path[i]].weight);
if(i!=num-1) printf(" ");
else printf("\n");
}
return;
}
else return;
}
else{
for(int i=0;i<nodes[index].child.size();i++)
{
int child = nodes[index].child[i];
path[num] = child;
DFS(child,num+1,sum+nodes[child].weight);
}
}
}
int main()
{
int t,n,c;
scanf("%d%d%d",&N,&M,&S);
for(int i=0;i<N;i++)
{
scanf("%d",&nodes[i].weight);
}
for(int i=0;i<M;i++)
{
scanf("%d%d",&t,&n);
for(int j=0;j<n;j++)
{
scanf("%d",&c);
nodes[t].child.push_back(c);
}
sort(nodes[t].child.begin(),nodes[t].child.end(),cmp);
}
path[0]=0;
DFS(0,1,nodes[0].weight);
return 0;
}