题目描述
相信大家对背包问题都了如指掌了,现在就给大家出一个非常简单的背包问题。
给出一颗n个结点的有根树,1号结点作为树根。每个结点有一个物品,物品有体积vi。q次询问,每次询问给出一个u和
m,问是否可以从u的子树中选一些物品使它们的体积和等于m。
输入
第一行一个整数n,表示结点总数
接下来n个整数vi,表示i号结点物品的体积
接下来n-1行,每行两个整数x,y,表示x,y之间有一条边
接下来一行一个整数q,表示询问个数
接下来q行,每行2个整数u,m,表示查询u的子树能否选一些物品使它们的总体积构成m
数据范围:1<=n<=2000, 1<=vi<=100, 1<=x,y<=n, 1<=q<=10000, 1<=u<=n, 1<=m<=2000。
输出
如果能构成m,输出YES
否则,输出NO
样例输入
5
1 2 3 4 5
1 2
2 3
2 4
1 5
5
2 7
2 8
5 5
1 10
3 7
样例输出
YES
NO
YES
YES
NO
思路
将输入的每一个根结点展成一个一维数组,然后转换为01背包问题
#include<iostream>
#include<vector>
using namespace std;
const int maxn=2020;
struct node{
int vul;
vector<int> child; //存放子节点下标
}Node[maxn];
int m; //给定的m
int n; //结点个数
void create(){ //建立这棵树,注意不一定是二叉树
int a,b;
for(int i=1;i<n;i++){ //n-1条边
cin>>a>>b;
Node[a].child.push_back(b);
}
}
vector<node> vi; //用来存放u的所有子节点(包括子节点的子节点及自身)
void preOrder(int root){ //利用先序存放
vi.push_back(Node[root]);
for(int i=0;i<Node[root].child.size();i++){
preOrder(Node[root].child[i]);
}
}
//下面对vector中元素进行01背包的递归算法
bool flag;
void DFS(int index,int sumv){
if(index==vi.size()){ //已经处理完vector里的物品
if(sumv==m){
flag=true;
return;
}
//cout<<"No"<<endl;
return;
}
DFS(index+1,sumv); //不选vector中的index号结点
DFS(index+1,sumv+vi[index].vul); //选
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>Node[i].vul;
}
create();
int query;
cin>>query;
while(query--){
vi.clear();
flag=false;
int u;
cin>>u>>m;
preOrder(u);
/*for(int i=0;i<vi.size();i++){
cout<<vi[i].vul<<" ";
}*/
//此时vector中存放u及u的子节点
DFS(0,0);
if(flag) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
return 0;
}