E. Demiurges Play Again Codeforces Round #300 思维

62 篇文章 0 订阅
10 篇文章 0 订阅

题目链接: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;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值