把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

JLOI2015 战争调度【树形dp】

题目链接

题目解析

乍一想有22n种状态,直接暴力不太可取。

考虑树dp的话,设dp[i]表示子树i的答案,由于有个m的限制,我们设dp[i][j]表示子树i内有j个人选择作战的最大贡献。

但是这样很难转移,因为我们不知道儿子们选了啥。

但如果从儿子们的角度来考虑,若一个叶结点的所有祖先结点的状态确定,那么这个叶结点的贡献可以直接算出来。而每个叶结点有2n1个祖先,如果枚举它们的祖先的状态,复杂度消耗只有2n1,再乘上叶结点个数,时间复杂度是2n1×2n1=2n

所以相当于可以枚举一条链上的每个点的状态,用类似于状压的方式存状态,然后到了叶子结点可以转移上去。

(我在想这样枚举复杂度不是狂野的22n应该是因为,它是按照父子关系枚举下来的,按照每一条链的顺序枚举下来,左右儿子通过dp的方式合并答案,而不是像直接暴力那样,链与链之间通过枚举状态计算答案,(有点像背包那个意思),把链与链之间的复杂度从加法变成了乘法)

每个点还有转移dp[u][i+j]=max(dp[u<<1][i]+dp[u<<1|1][j]),这里还有个n的复杂度,所以总时间复杂度应该是O(n2n)


►Code View

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
#define LL long long
#define N 15
#define K 5000
#define INF 0x3f3f3f3f
int rd()
{
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48); c=getchar();}
	return f*x;
}
int n,m,k,ans;
int w[K][N],f[K][N];//war farm 
int dp[K][K];//以i为根的子树内有j个平民作战的最大贡献 
void dfs(int u,int s,int d)//u为子树根节点 s为祖先的状态(状压 1作战 0后勤) d为子树大小 
{
	for(int i=0;i<=d;i++)
		dp[u][i]=0;
	//记得清空 下面的dp值在根选另一个选项时算过 
	if(d==1)
	{//叶子结点 
		for(int i=0;i<n-1;i++)
		{//枚举n-1个祖先 高位是比较老的祖先 爸爸是最低位 
			if((s>>i)&1)//第i个祖先作战 
				dp[u][1]+=w[u-(k-1)][i+1]; 
			else dp[u][0]+=f[u-(k-1)][i+1];
		}
		return ;
	}
	for(int sit=0;sit<=1;sit++)
	{//枚举当前为作战/后勤 
		dfs(u<<1,(s<<1)|sit,d>>1);
		dfs(u<<1|1,(s<<1)|sit,d>>1);
		for(int i=0;i<=min(d,m);i++)
			for(int j=0;j<=min(d,m);j++)
				dp[u][i+j]=max(dp[u][i+j],dp[u<<1][i]+dp[u<<1|1][j]); 
	}
} 
int main()
{
	n=rd(),m=rd();
	k=1<<(n-1);//叶子结点个数 
	for(int i=1;i<=k;i++)
		for(int j=1;j<=n-1;j++)
			w[i][j]=rd();
	for(int i=1;i<=k;i++)
		for(int j=1;j<=n-1;j++)
			f[i][j]=rd();
	dfs(1,0,(1<<n)-1);
	for(int i=0;i<=m;i++)
		ans=max(ans,dp[1][i]);
	printf("%d\n",ans); 
	return 0;
}
posted @   Starlight_Glimmer  阅读(81)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
浏览器标题切换
浏览器标题切换end
点击右上角即可分享
微信分享提示