题目描述
相信大家对背包问题都了如指掌了,现在就给大家出一个非常简单的背包问题。
给出一颗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<=105, 1<=vi<=109, 1<=x,y<=n, 1<=q<=105, 1<=u<=n, 1<=m<=1018。
输出
对于每个询问,输出一行一个整数,表示答案。
样例输入
5
1 2 3 4 5
1 2
2 3
2 4
1 5
5
2 7
1 3
1 15
5 4
4 5
样例输出
2
2
5
0
1
思路
将输入的每一个根结点展成一个一维数组,然后转换为01背包问题
在上个发出来的完全背包的基础上改动,只改动了DFS算法
#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背包的递归算法
int maxNum=0;
void DFS(int index,int sumv,int num){ //sumv是目前体积,num是目前选择物品个数
if(index==vi.size()){ //已经处理完vector里的物品
if(sumv<=m&&num>maxNum){
maxNum=num;
return;
}
return;
}
DFS(index+1,sumv,num); //不选vector中的index号结点
DFS(index+1,sumv+vi[index].vul,num+1); //选
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>Node[i].vul;
}
create();
int query;
cin>>query;
while(query--){ //query次询问
vi.clear();
//flag=false;
maxNum=0;
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,0);
cout<<maxNum<<endl;
}
return 0;
}