E. Demiurges Play Again Codeforces Round #300 思维
题目链接:http://codeforces.com/problemset/problem/538/E
题意:
给你一棵根为1的树,现在点1的位置上有一个球,两个人A和B轮流将球往下一层推,直到不能再推为止,假设这棵树一共有m个叶子结点,你可以在这m个结点上随意的放上数字1-m,在你放完之后,A和B开始推球,A希望球最后停的叶子上的数字越大越好,B希望这个数字越小越好,由A先开始推球。现在由你来先进行数字分配,来找出A和B在最优策略下最终能达到的最大值和最小值。
做法:
也算是想出来了,但是代码的话和大神比起来还是繁杂了点...很明显有点像树形dp吧..咳咳
为了更清楚,我画了一张丑丑的图。
我们假设现在要找到这个最大值,假设当B在走,现在B在位置12上,它当然希望能走到越小的地方越好,所以它会走到13,14,15三个位置上的最小值,也隐含着的意思是,我们答案的最大值的代价是-3?我们在看子树2上的其他位置,如果B走到了3,那么等于把选择权利交给了A,那么如果我们把最大值放到7,A一定会选择7,所以B走到位置3的时候代价为-1。这个代价是什么意思呢,就是我选择这个子树对最大值的减少量,假设B在结点2,val[6]是这颗子树上所有结点的最大值,val[16]是第二大,val[7]是第三大,13,14,15分别为第四、五、六大,那么B一定会选位置4的路径,这样能保证自己能控制的情况下最大值最小,也就是说,B在求最大值的时候要加上所有子树的代价,而A在选择的时候一定会选择所有子树中代价的最小值,因为他希望这个最大值最大。求最小值的时候,两个人的目标换一下,策略也就会换一下,在最大值的时候再稍作处理就好乐。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=(int) 1e8;
const int maxn=200005;
struct edge{
int to,nex;
}e[maxn<<1];
int head[maxn],cnt,n,lef;
int sz[maxn],dep[maxn];
int minn[maxn];
void add(int u,int v){
e[cnt].to=v,e[cnt].nex=head[u];
head[u]=cnt++;
}
void init(int u,int fa){
sz[u]=1;
for(int i=head[u];~i;i=e[i].nex){
int v=e[i].to;
if(v==fa) continue;
dep[v]=dep[u]+1;
init(v,u);
sz[u]+=sz[v];
}
if(sz[u]==1) lef++;
}
int dfs(int u,int fa,int f){
int ret=1;
if(sz[u]>1){
if(f==dep[u]%2) ret=inf;
else ret=0;
}
for(int i=head[u];~i;i=e[i].nex){
int v=e[i].to;
if(v==fa) continue;
if(f==dep[u]%2) ret=min(ret,dfs(v,u,f));
else ret+=dfs(v,u,f);
}
minn[u]=ret;
return ret;
}
int main(){
memset(head,-1,sizeof(head));
scanf("%d",&n);
for(int i=1;i<n;i++){
int a,b;
scanf("%d%d",&a,&b);
add(a,b); add(b,a);
}
if(n==1){
printf("1 1\n");
return 0;
}
dep[1]=1;
init(1,-1);
dfs(1,-1,1);
int fians=0;
for(int i=head[1];~i;i=e[i].nex){
int v=e[i].to;
fians=max(fians,lef-minn[v]+1);
}
printf("%d %d\n",fians,dfs(1,-1,0));
return 0;
}