战争调度

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/Tan_tan_tann/article/details/102688513

战争调度

题解

这道题最开始想到的是爆搜,但想着想着就成树形dp了。

我们令dp_{ij}为第i个节点的子树上有j人打仗的贡献值及其祖先的最大值。

那非叶节点i的值为 dp_{x,i+j}= max\left (dp_{x*2,i}+dp_{x*2+1,j} \right )

我们在搜索整棵树时记录下该节点是否打仗,从叶子节点开始更新当前最大值。

最后找到最大的max(dp_{1,i})(i\leq m)

源码

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream> 
#include<algorithm>
#include<stack>
#include<vector>
using namespace std;
typedef long long LL;
const LL INF=0x3f3f3f3f;
LL n,m,ans=0;
LL w[1500][20],f[1500][20];
LL dp[1500][1500];
bool vis[15];
/*#define gc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<22,stdin),p1 == p2)?EOF:*p1++)
char buf[(1<<22)],*p1=buf,*p2=buf;*/
#define gc() getchar()
template<typename _T>
inline void read(_T &x)
{
	_T f=1;x=0;char s=gc();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=gc();}
	while(s>='0'&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=gc();}
	x*=f;
}//读优
void dfs(LL x,LL y)
{
	//printf("%d %d\n",x,y);
	for(LL i=0;i<=1<<y;i++) dp[x][i]=0;
	if(!y)
	{
		for(LL i=1;i<=n;i++)
			if(vis[i]) dp[x][1]+=w[x][i];
			else dp[x][0]+=f[x][i];
		return ;
	}//更新当前叶节点
	vis[y]=0;dfs(x<<1,y-1);dfs(x<<1|1,y-1);//不打仗
	for(LL i=0;i<=1<<(y-1);i++)
		for(LL j=0;j<=1<<(y-1);j++)
			dp[x][i+j]=max(dp[x][i+j],dp[x<<1][i]+dp[x<<1|1][j]);//返回更新
	vis[y]=1;dfs(x<<1,y-1);dfs(x<<1|1,y-1);//打仗
	for(LL i=0;i<=1<<(y-1);i++)
		for(LL j=0;j<=1<<(y-1);j++)
			dp[x][i+j]=max(dp[x][i+j],dp[x<<1][i]+dp[x<<1|1][j]);//返回更新
}
int main()
{
	read(n);read(m);n--;
	for(LL i=0;i<(1<<n);i++)
		for(LL j=1;j<=n;j++)
			read(w[i+(1<<n)][j]);
	for(LL i=0;i<(1<<n);i++)
		for(LL j=1;j<=n;j++)
			read(f[i+(1<<n)][j]);
	dfs(1,n);
	for(LL i=0;i<=m;i++)
		ans=max(dp[1][i],ans);//找答案
	printf("%lld",ans);
	return 0;
}


谢谢!!!

猜你喜欢

转载自blog.csdn.net/Tan_tan_tann/article/details/102688513