版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
战争调度
题解
这道题最开始想到的是爆搜,但想着想着就成树形dp了。
我们令为第i个节点的子树上有j人打仗的贡献值及其祖先的最大值。
那非叶节点i的值为
我们在搜索整棵树时记录下该节点是否打仗,从叶子节点开始更新当前最大值。
最后找到最大的
源码
#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;
}