1053 Path of Equal Weight (30分)
//给定一棵树和每个节点的权值
//求所有从根节点到叶子节点的路径
//使得每条路径上的节点的权值之和等于给定的常数S
//如果有多条这样的路径
//按照路径非递增的顺序输出
//其中路径的大小是指,如果有两条路径分别为a1->a2->...ai->an和b1->b2->b3->...bi->bm
//如果ak>bk,则称第一条路径大------>递减,编号大的先输出
#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
struct node{
int w;
vector<int> child;
}Node[110];
int n,m,S;
int path[110];//记录路径
void dfs(int index,int depth,int sum){
if(sum>S)return;
if(sum==S){
//当前sum和为s
if(Node[index].child.size()!=0)return;//还没到达叶子节点,直接返回
//到达了叶子节点,此时path[]中存放了一条完整的路径,输出它
else{
for(int i=0;i<depth;i++){
printf("%d",Node[path[i]].w);//
if(i<depth-1)printf(" ");
else printf("\n");
}
return ;
}
}
for(int i=0;i<Node[index].child.size();i++){
int child=Node[index].child[i];//节点index的第i个子节点的编号--孩子编号
path[depth]=child;//path下标从0开始,层数从1开始,下标是层数,元素是下一个要遍历的孩子编号
dfs(child,depth+1,sum+Node[child].w);
}
}
bool cmp(int a,int b){
return Node[a].w>Node[b].w;//将某一节点的孩子节点,按节点的点权从大到小排序
}
int main()
{
scanf("%d%d%d",&n,&m,&S);
for(int i=0;i<n;i++){
scanf("%d",&Node[i].w);
}
int id_father,num_child,id_child;
for(int i=0;i<m;i++){
cin>>id_father>>num_child;
for(int j=0;j<num_child;j++){
cin>>id_child;
Node[id_father].child.push_back(id_child);
}
sort(Node[id_father].child.begin(),Node[id_father].child.end(),cmp);//排序 // ?????????按节点的点权从大到小排序,默认是升序,从小到大,所以需要重写cmp
}
path[0]=0;//路径的第一个节点设置为0号节点,因为我们求的是从根节点到孩子节点的路径
dfs(0,1,Node[0].w);//根节点是0,在第一层(Ai---A1,A2....),路径总权重是10
return 0;
}
--------------
#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
struct node{
int w;//点权
vector<int> child;//孩子节点
}Node[110];
int n,m,s;
int path[110];//记录路径
void dfs(int index,int depth,int sum){
//我们要求从根节点到叶子节点的路径长度为s的方案
if(sum>s)return;
if(sum==s){
if(Node[index].child.size()!=0)return;//路径的长度到了s,但是没有路要走,没到达孩子节点,不符合题意,去掉
else{
//到达了孩子节点并且路径长度为s,是我们要求的
for(int i=0;i<depth;i++){
printf("%d",Node[path[i]].w); // path[depth]=child;
if(i<depth-1)printf(" ");
else printf("\n");
}
return;
}
}
//sum<s//还没到达规定的路径长度,继续递归找孩子
for(int i=0;i<Node[index].child.size();i++){
//有几个孩子
int child=Node[index].child[i];//第几个孩子
path[depth]=child;
dfs(child,depth+1,sum+Node[child].w);
}
}
bool cmp(int a,int b){
//a,b都是某个节点的孩子的编号//对某一结点的孩子节点,按照点权大小排序
//10 5 2 7
//10 4 10
// scanf("%d",&Node[i].w);//输入每个节点的点权--结构体
return Node[a].w>Node[b].w;
}
int main()
{
scanf("%d%d%d",&n,&m,&s);//20 9 24
for(int i=0;i<n;i++){
//节点编号从0开始,i代表节点编号
scanf("%d",&Node[i].w);//输入每个节点的点权--结构体
}
int id_father,num_child,id_child;
for(int i=0;i<m;i++){
//给出有孩子节点的节点的信息----编号要用id_father
cin>>id_father>>num_child;
for(int j=0;j<num_child;j++){
//孩子的个数....孩子的点权
cin>>id_child;//00 4
Node[id_father].child.push_back(id_child);//01 02 03 04
}
sort(Node[id_father].child.begin(),Node[id_father].child.end(),cmp);//04 03 02 01
}
path[0]=0;
dfs(0,1,Node[0].w);//根节点编号,路径的下标(A1,A2..),总权重(现在仅仅只有根节点的点权)
return 0;
}
这道题dfs遍历树,和以往做的题目不太一样,传入了sum这个形参,这是由于题目而调整的
因此递归条件也和sum这个参数有关
这个题目让我想到了一道题—背包,因为背包也是传入多个参数,而且那些参数,我都不太懂,所以来分析一下
例子:背包价值最大
//有n件物品,每件物品的重量是w[i],价值是c[i],现需要选出若干物品放入一个容量为V的背包里,
//使的在选入背包的物品重量和不超过容量v的前提下,让背包物品的价值之和最大,求最大价值(1<=n<=20)
void DFS(int index,int sumW,int sumC)
//有n件物品,每件物品的重量是w[i],价值是c[i],现需要选出若干物品放入一个容量为V的背包里,
//使的在选入背包的物品重量和不超过容量v的前提下,让背包物品的价值之和最大,求最大价值(1<=n<=20)
//输入数据:
//5 8//5件物品,背包容量为8
//3 5 1 2 2 //重量分别是3 5 1 2 2
//4 5 2 1 3//价值分别是4 5 2 1 3
//输出结果
//10
#include <iostream>
#include <cstdio>
using namespace std;
const int maxn=50;
int n,v,maxSumW=0;//物品件数n,背包容量v
int w[maxn],c[maxn];//w[i]为每一件物品的重量,c[i]为每一件物品的价值
void dfs(int index,int sumW,int sumC){
// if(sumW>v)return;
// else if(sumW==v){
// }
if(index==n){
//每次都要对物品进行选择,选择最佳方案
if(sumW<=v&&sumC>maxSumW)
maxSumW=sumC;
return;
}
dfs(index+1,sumW,sumC);
dfs(index+1,sumW+w[index],sumC+c[index]);
}
int main()
{
scanf("%d%d",&n,&v);
for(int i=0;i<n;i++){
scanf("%d",&w[i]);//每件物品的重量
}
for(int i=0;i<n;i++){
scanf("%d",&c[i]);
}
dfs(0,0,0);//初始化为第0件物品,当前总重量和总价值均为0
printf("%d",maxSumW);
return 0;
}