codeforces #300 E-Demiurges Play Again

传送门:点击打开链接

dp好题,难点在于递推关系不太直观,需要静下来分析。

设A是每次取最大的,B是每次取最小的,Max模式是使结果尽可能大的安排方式,Min模式是使结果尽可能小的安排方式
按题目的需求有4种状态:
A-Max
A-Min
B-MAx
B-Min
最直观的是A-Max和B-Min,以A-Max为例,要使得当前子树的取值最大,那么会把编号最大的点都放到这课子树上。并且A-Max和B-Min是一种对偶关系,满足Va+Vb=Cap+1(Cap是所有叶子节点的个数)
现在考虑剩下的两种情况,A-Min的所有子决策是B-Min,上面已经说过,B-Min在对于单独的一颗子树来说会把所有编号最小的点放在这课子树上。假设这样得到的值为V[s1],V[s2]..V[sk],但是A-Min并不是取这些值中的最大值,因为每个编号只能用一次。可以知道当V[s1]被满足时,所有编号小于等于V[s1]的点都被放到了这s1这课子树上,因而对于s2来说,可以取到的值就变成了V[s2]+V[s1]。所以最后可以得到A-Min=Sum(V[si])。
在Min模式下,所有A的取值方式被安排得尽可能平均,所以B-Min=min(V[si])

以上。

#include<iostream>
#include<string.h>
#include<stdio.h>
#include<vector>
using namespace std;

vector<int> G[200005];
int dp[200005][2];

void dfs(int p){
	if(G[p].size()==0){
		dp[p][0]=1;
		dp[p][1]=1;
		return;
	}
	dp[p][0]=0;dp[p][1]=1000000000;
	for(int i=0;i<G[p].size();i++){
		int to=G[p][i];
		dfs(to);
		dp[p][0]+=dp[to][1];
		dp[p][1]=min(dp[p][1],dp[to][0]);
	}
}

int main(){
	int n;
	int i,j;
	int x,y;
	scanf("%d",&n);
	for(i=1;i<n;i++){
		scanf("%d%d",&x,&y);
		G[x].push_back(y);
	}
	int c=0;
	for(i=1;i<=n;i++){
		if(G[i].size()==0){
			c++;
		}
	}
	dfs(1);
	printf("%d %d\n",c+1-dp[1][1],dp[1][0]);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值