作为一个刷题的萌新来说,这题简直太难了。
从网上看了大佬的博客,看了好久(参考博客连接在文末)。
这道题结合了深搜和dp。
从题目里我还学到了用位移位运算的方便快捷。>> <<
从大佬的博客中,我学习到:对于叶子结点来说,当祖先结点的状态确定时,根据贡献值,他参战与否就能确定。那么我们从根结点到叶节点深搜,每向叶节点靠近一层,就确定当前这个结点的状态。当达到叶结点时,根据祖先结点的状态,就能确定他参战或是后勤的总贡献。在回溯时,每回溯一层,求得当前结点为根时,不同叶子参战数的贡献值。
#include <stdio.h>
#include <math.h>
int war[1024][10];
int farm[1024][10];
int node=0;//子结点的数量
int state;//上层节点的状态
int dp[1024][513];
int n,m;
void DFS(int x);
int max(int a,int b);
int main() {
int i,j;//计数
int ans=0;
scanf("%d %d",&n,&m);
for(i=0; i<(1<<n>>1);i++)
for(j=0; j<n-1; j++)
scanf("%d",&war[i][j]);
for(i=0; i<(1<<n>>1);i++)
for(j=0; j<n-1; j++)
scanf("%d",&farm[i][j]);
node=1<<n>>1;
state=0;
DFS(1);
for(i=0;i<=m;i++)
ans=max(ans,dp[1][i]);
printf("%d",ans);
return 0;
}
void DFS(int x){
int i,j,k;
int tmp;
for(i=0;i<=node;i++)
dp[x][i]=0;
if(node==1){
tmp=1<<n>>1;
for(i=0;i<n-1;i++){
if(state>>i&1){
dp[x][1]+=war[x-tmp][i];
}else{
dp[x][0]+=farm[x-tmp][i];
}
}
return;
}
node>>=1;
state<<=1;//当前不参战
DFS(x<<1);
DFS(x<<1|1);
for(j=0;j<=node;j++){
for(k=0;k<=node;k++){
dp[x][j+k]=max(dp[x][j+k],dp[x<<1][j]+dp[x<<1|1][k]);
}
}
state|=1;//当前参战
DFS(x<<1);
DFS(x<<1|1);
for(j=0;j<=node;j++){
for(k=0;k<=node;k++){
dp[x][j+k]=max(dp[x][j+k],dp[x<<1][j]+dp[x<<1|1][k]);
}
}
state>>=1;
node<<=1;
}
int max(int a,int b){
return a>b?a:b;
}
参考博客:https://blog.csdn.net/qq_42101694/article/details/102689715