习题:战争调度(dp)

 

题目

传送门

思路

dp[i][j]表示以i号节点为根节点字数有j个平民参加战争的最大值
$ans=\max_{i=1}^{n}dp[1][i]$
那么考虑转移
额,貌似也很简单
考场上怎么都A不了
$dp[i][j]=max_{i=0}^{size}dp[lson][j-i]+dp[rson][i]$

那么初始化呢?
因为子树之间是独立的,所以只需要考虑他们父亲所构成的链就行了
那么问题来了,是否需要将链记忆化呢?
很明显意义不大,因为每个链之间没有太大的联系,
如果记忆化空间也会炸,我太难了啊!!!

代码

#include<iostream>
#include<cstring>
using namespace std;
#define int long long
int n;
int m;
int qkpow(int a,int b)
{
	if(b==0)
		return 1;
	if(b==1)
		return a;
	int t=qkpow(a,b/2);
	t*=t;
	if(b%2==1)
		t*=a;
	return t;
}
int w[1050][10];
int f[1050][10];
int dp[1050][1050];
int ans=0;
bool vis[1050];
void dfs(int u,int depth)
{
	for(int i=0;i<=(1<<depth);i++)
		dp[u][i]=0;
	if(depth==0)
	{
		for(int i=1;i<=n;i++)
		{
			if(vis[i])
				dp[u][1]+=w[u][i];
			else
				dp[u][0]+=f[u][i];
		}
		return;
	}
	vis[depth]=0;
	dfs(u<<1,depth-1);
	dfs(u<<1|1,depth-1);
	for(int i=0;i<=(1<<depth-1);i++)
	{
		for(int j=0;j<=(1<<depth-1);j++)
		{
			if(i+j>m)
				break;
			dp[u][i+j]=max(dp[u][i+j],dp[u<<1][i]+dp[u<<1|1][j]);
		}
	}
	vis[depth]=1;
	dfs(u<<1,depth-1);
	dfs(u<<1|1,depth-1);
	for(int i=0;i<=(1<<depth-1);i++)
	{
		for(int j=0;j<=(1<<depth-1);j++)
		{
			if(i+j>m)
				break;
			dp[u][i+j]=max(dp[u][i+j],dp[u<<1][i]+dp[u<<1|1][j]);
		}
	}
}
signed main()
{
	cin>>n>>m;
	for(int i=0;i<(1<<n-1);i++)
		for(int j=1;j<n;j++)
			cin>>w[i+(1<<n-1)][j];
	for(int i=0;i<(1<<n-1);i++)
		for(int j=1;j<n;j++)
			cin>>f[i+(1<<n-1)][j];
	dfs(1,n-1);
	for(int i=0;i<=m;i++)
		ans=max(ans,dp[1][i]);
	cout<<ans;
	return 0;
}
posted @ 2019-10-22 20:45  loney_s  阅读(134)  评论(0)    收藏  举报