聚变反应炉

读完题过后,我们发现n大的数据c只有0或者1的情况,很显然是要我们分类讨论,(如果不分类只有80分,会T)

我们换一个角度来看这道题的答案

他让我们求出按顺序点亮一些点,然后总共的花费是多少

我们可以视作我们已经点了所有点,然后按顺序点一些点,最后最多能减少多少的花费

case 1:(c只有0或者1)

很显然是把1的点优先点亮,然后再点0的点

模拟一下即可

for(i=1;i<=n;++i)
if(c[i]){   //如果是1
	ans=ans+d[i];    //加上花费
	d[i]=0;        //花费搞成0
	for(j=head[i];!!j;j=nex[j])
	--d[to[j]];     //相邻的点-1
}
for(i=1;i<=n;++i)
if(d[i]>0)ans=ans+d[i];//点亮为0的点
printf("%d
",ans);

case 2:

我们假设要求x

那么我们可以有两种情况

1.我们先点亮fa[x]再点亮x

2.我们先点亮x再点亮fa[x]

那么我们就设f[x][0/1] 表示情况2/1

那么我们考虑如何求出f[x][0/1]

我们在设tmp[i] 表示x收到了来自儿子的i能量,把子树搞好的最小价值

就可以轻松求出f[x][0/1]

那么现在的问题是求出tmp[i]

很显然我们可以用滚动数组+背包求出来

(tmp[now][i]=min(f[y][0]+tmp[now space xor space 1][i-c[y]],f[y][1]+tmp[now space xor space 1][i]))

然后就完了

inline void dfs(int x,int ne){
	int i,sum(0),y;
	for(i=head[x];!!i;i=nex[i]){
		y=to[i];
		if(y==ne)continue;
		dfs(y,x);
		sum=sum+c[y];
	}
	int now(0),j;
	memset(tmp[now],63,sizeof(tmp[now]));
	tmp[now][0]=0;
	for(i=head[x];!!i;i=nex[i]){
		y=to[i];
		if(y==ne)continue;
		now^=1;
		memset(tmp[now],63,sizeof(tmp[now]));
		for(j=sum;j>=0;--j){
			if(j+c[y]<=sum)tmp[now][j+c[y]]=min(tmp[now][j+c[y]],tmp[now^1][j]+f[y][0]);
			tmp[now][j]=min(tmp[now][j],tmp[now^1][j]+f[y][1]);
		}
	}
	memset(f[x],63,sizeof(f[x]));
	for(i=0;i<=sum;++i)
	f[x][0]=min(f[x][0],max(tmp[now][i],tmp[now][i]+d[x]-i)),
	f[x][1]=min(f[x][1],max(tmp[now][i],tmp[now][i]+d[x]-i-c[ne]));
}

代码

#include<bits/stdc++.h>
#define N 100011
#define M 200011
#define MAXSUM 501011
using namespace std;
int head[N],nex[M],to[M],tot;
inline void build(int x,int y){
	to[++tot]=y;
	nex[tot]=head[x];
	head[x]=tot;
}
int d[N],c[N];
int tmp[2][MAXSUM],n,f[N][2];
inline void dfs(int x,int ne){
	int i,sum(0),y;
	for(i=head[x];!!i;i=nex[i]){
		y=to[i];
		if(y==ne)continue;
		dfs(y,x);
		sum=sum+c[y];
	}
	int now(0),j;
	memset(tmp[now],63,sizeof(tmp[now]));
	tmp[now][0]=0;
	for(i=head[x];!!i;i=nex[i]){
		y=to[i];
		if(y==ne)continue;
		now^=1;
		memset(tmp[now],63,sizeof(tmp[now]));
		for(j=sum;j>=0;--j){
			if(j+c[y]<=sum)tmp[now][j+c[y]]=min(tmp[now][j+c[y]],tmp[now^1][j]+f[y][0]);
			tmp[now][j]=min(tmp[now][j],tmp[now^1][j]+f[y][1]);
		}
	}
	memset(f[x],63,sizeof(f[x]));
	for(i=0;i<=sum;++i)
	f[x][0]=min(f[x][0],max(tmp[now][i],tmp[now][i]+d[x]-i)),
	f[x][1]=min(f[x][1],max(tmp[now][i],tmp[now][i]+d[x]-i-c[ne]));
}
int main( ){
	scanf("%d",&n);
	int i,j,k;
	int x,y,z,maxc(0);
	for(i=1;i<=n;++i)
	scanf("%d",&d[i]);
	for(i=1;i<=n;++i){
		scanf("%d",&c[i]);
		maxc=max(maxc,c[i]);
	}
	for(i=1;i<n;++i){
		scanf("%d%d",&x,&y);
		build(x,y);
		build(y,x);
	}
	int ans(0);
	if(maxc<=1){
		for(i=1;i<=n;++i)
		if(c[i]){
			ans=ans+d[i];
			d[i]=0;
			for(j=head[i];!!j;j=nex[j])
			--d[to[j]];
		}
		for(i=1;i<=n;++i)
		if(d[i]>0)ans=ans+d[i];
		printf("%d
",ans);
		return 0;
	}
	dfs(1,0);
	printf("%d
",f[1][0]);
}
原文地址:https://www.cnblogs.com/the-Blog-of-Mikasa/p/14006404.html