树上背包。

一,定义

对于求取一棵树上的背包问题,可以由子树推到整棵树的情况

例题一:Problem - 1011 (hdu.edu.cn)

思路:模板题

  1. 对子树遍历最优直到整颗树获得最优即可 

  2. 按照题意,即使没有虫子,你必须还有剩余士兵才可以往下走,所有dfs进入一个点时,必须当前还有士兵才可以进入(特别是一开始就m=0的情况)

  3. 我们在用子树v更新当前树u时,子代也必须从dp[u][j]的j>=1开始,即至少派一个士兵去子树的情况

#include 
using namespace std;
#define ll               long long
#define endl             "\n"
const int N = 110;
vectoredge[N];
int a[N],b[N],dp[N][N];

void dfs(int u,int f,int w)
{
	if(!w||a[u]>w)return;
	for(int i=a[u]; i<=w; ++i)dp[u][i]=b[u];//先初始化一开始经过这个点获得这个点的val值
	for(auto v:edge[u])if(v!=f)
			{
				dfs(v,u,w-a[u]);//更新子树,记得j从1开始,至少有一个士兵去子树
				for(int i=w; i>=a[u]; --i)for(int j=i-a[u]; j>=1; --j)dp[u][i]=max(dp[u][i],dp[u][i-j]+dp[v][j]);
			}
}

void mysolve()
{
	int n,m;
	while(cin>>n>>m&&(n!=-1||m!=-1))
		{
			memset(dp,0,sizeof(dp));
			for(int i=1; i<=n; ++i)edge[i].clear(),cin>>a[i]>>b[i],a[i]=(a[i]+19)/20;
			int x,y;
			for(int i=1; i>x>>y,edge[x].push_back(y),edge[y].push_back(x);
			dfs(1,0,m);
			cout<> t;
	while (t--)
		{
			mysolve();
		}
	system("pause");
	return 0;
}

例题二:Problem - 4003 (hdu.edu.cn)

思路:

  1. 我们可以用dp[u][j]表示在u节点全部点便利后,有j个机器留在u子树里面。显然j=0,就是来了一个机器而且他遍历完还走了。
  2. 我们应清楚,不会有来了超过一个机器还都走了的情况(要有机器走就只来一个机器,来多就全部留着这里),因为遍历子树就是把子树所有边都走两遍,显然一个机器走就行
  3. 我们清楚,对于一个子树,其最坏情况就是来了一个机器然后走了,其余的只会更优
#include 
using namespace std;
#define ll               long long
#define endl             "\n"
typedef pair pii;
const int N = 2e4 + 10;

vectoredge[N];
int dp[N][15];
int n,s,k;
void dfs(int u,int f)
{
	for(pii h:edge[u])if(h.first!=f)
			{
				int v=h.first,w=h.second;
				dfs(v,u);
				for(int i=k; i>=1; --i)
					{
						dp[u][i]+=dp[v][0]+2*w;//最坏代价就是一个机器进去还出来,来回各走一次u-v路径w
						for(int j=i; j>=1; --j)dp[u][i]=min(dp[u][i],dp[u][i-j]+dp[v][j]+w*j);//枚举多个机器留着子树,进行更新,要加上j个机器进去时经过u-v路径w
					}
				dp[u][0]+=dp[v][0]+2*w;//存储只有一个机器的情况
			}
}
void mysolve()
{
	while(cin>>n>>s>>k)
		{
			memset(dp,0,sizeof(dp));
			for(int i=1; i<=n; ++i)edge[i].clear();
			int x,y,w;
			for(int i=1; i>x>>y>>w,edge[x].push_back({y,w}),edge[y].push_back({x,w});
			dfs(s,0);
			cout<> t;
	while (t--)
		{
			mysolve();
		}
	system("pause");
	return 0;
}

你可能感兴趣的:(动态规划,算法,c++,数据结构)