偷天换日

//T2 偷天换日
//dp还是最短路? 
//其实就是二叉树形套了个背包? 
//分成两块,左右子树,展厅里跑DP 
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int mx=700;
int n;
int nn=1;
ll w[mx*mx];
ll c[mx*mx];
ll f[mx][mx];//f[i][j] 以i为根,用时j的最大价值 
void dfs(int rt){
	ll t;
	int x;
	scanf("%lld%d",&t,&x);
	t=t*2;//细节 
	if(x>0){
		for(int i=1;i<=x;++i){
			scanf("%lld%lld",&w[i],&c[i]);//价值w,用时c 
		}
		for(int i=1;i<=x;++i){
			for(int j=n;j>=c[i]+t;--j){//写上面还快一点 
				   f[rt][j]=max(f[rt][j],f[rt][j-c[i]]+w[i]);
		//		   printf("f[%d][%d]=%lld\n",rt,j,f[rt][j]); 
			}
		}
	}
	else {
	/*	nn++;
		dfs(rt+1);
		nn++;
		dfs(rt+2);*/
		nn++;
		int ls=nn;
	//	printf("nn=%d rt+1=%d\n",nn,rt+1);
		dfs(nn);
		nn++;
		int rs=nn;
		dfs(nn);
		//关于为什么不能用rt+1,rt+2 
		//因为它是按照深度优先给的输出,所以我们边深度优先边建树 
		//在建树的时候
		//一的左右儿子可不是2 3 而是2 2深完了之后的值+1 是它,所以得用nn 
		//左右子树开始轮时间
		//最后确认一次,树形DP,左右子树轮时间
		//当到达叶子节点,用背包计算值,然后回溯
		//这样还是只能说,只是一个思路感觉,有什么细节我也不知道,写吧。。。 
		//总时间是n-t
		//f[rt][] 
		
		//为什么,用rt+1会爆,而ls,rs不会,我怎么也想不到是这错了 
		for(int i=t;i<=n;++i){
			for(int j=0;j<=i-t;++j){
				//轮的是时间,所以j直接0到i就行 
				//不对不对 
				f[rt][i]=max(f[rt][i],f[ls][i-j-t]+f[rs][j]);
		//		printf("1k f[%d][%d]=%lld n-t=%d\n",rt,i+j,f[rt][i+j],n-t);
			}
		}
//		f[rt][n]=f[rt][n-t];
	//	printf("f[%d][%d]=%lld\n",rt,n,f[rt][n]);
	}
}
void Solve(){
	scanf("%d",&n);
	n=n-1;//这里我调了半小时,我真是笑了,在这里恶心人
	dfs(1);
/*	for(int i=1;i<=nn;++i){
		printf("f[%d][%d]=%lld\n",i,n,f[i][n]);
	}*/
	printf("%lld\n",f[1][n]);
} 
int main(){
	freopen("steal.in","r",stdin);
	freopen("steal.out","w",stdout);
	Solve();
	return 0;
} 
posted @ 2022-02-21 11:21  SMTwy  阅读(79)  评论(0)    收藏  举报