• arc112c


    arc112c

    大意

    略...

    思路

    我们不妨假定 (d_i) 为先手走到第 (i) 个点的人,最优策略下与另一个人获得的硬币差。

    显然,该博弈为零和博弈,所以,我们要最小化 (d_1) 。(注意,首先行动的人可以直接拿走点1上的硬币,所以相当于后手到点 (i)

    开始讨论。

    (A) 先手走到 (i) ,定义为:

    如果 (i) 上有硬币,那么 (A) 拿不到硬币。

    如果 (i) 上没有硬币,那么 (A) 选择向哪棵子树走。

    不难发现,如果子树节点数为奇数,那么进去后会就交换先后手。

    依此,我们将以 (j) 为根的子树分为四种类型:

    1. (d_j >0) 且不会交换
    2. (d_j >0) 且会交换
    3. (d_jleq0) 且不会交换
    4. (d_j leq0) 且会交换

    我们不妨假设是人 (A) 先手走到点 (k) ,最优策略下, (A) 肯定先会将第一种类型的子树全部走遍。

    也不难发现,第三种类型的子树完全没有走的必要,又亏,又不交换,没有意义。

    所以,接下来,两人的最优策略就是贪心选择第二和第四种子树。

    这样最后的倒霉蛋就不得不把第三种子树全部选掉。

    代码

    #include <map>
    #include <set>
    #include <cmath>
    #include <queue>
    #include <cstdio>
    #include <vector>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    #define ll long long
    #define ull unsigned long long
    #define cint const int&
    #define Pi acos(-1)
    
    const int mod = 1e9+7;
    const int inf_int = 0x7fffffff;
    const ll inf_ll = 0x7fffffffffffffff;
    const double ept = 1e-9;
    
    int n;
    int h[100100], nx[200200], to[200200], ct;
    int siz[100100];
    int q[100100], cnt;
    
    void add(cint f, cint t) {
        nx[++ct] = h[f];
        h[f] = ct;
        to[ct] = t;
    }
    
    int dfs(cint loc, cint fa) {
        int r= -111;
        int ans = -1, oth = 0;
        vector<int > d;
        for(int i=h[loc]; i; i = nx[i])
            if(to[i] != fa) {
                r = dfs(to[i], loc);
                siz[loc] += siz[to[i]];
                if(!(siz[to[i]] & 1) && r > 0) ans += r;
                else if(!(siz[to[i]] & 1) && r < 0) oth += r;
                else if((siz[to[i]] & 1)) d.push_back(r);
            }
        int nt = d.size();
        for(int i=0; i<nt; i++) q[i+1] = d[i];
        sort(q+1, q+1+nt);
        for(int i=nt; i>=1; i--)
            if(!((nt-i) & 1)) ans += q[i];
            else ans -= q[i];
        if(nt & 1) ans -= oth;
        else ans += oth;
        return ans;
    }
    
    int main() {
        cin >> n;
        int r;
        for(int i=2; i<=n; i++) {
            cin >> r;
            add(r, i);
            add(i, r);
            siz[i] = 1;
        }
        cout << (n-dfs(1, 1))/2 << endl;
        return 0;
    }
    
  • 相关阅读:
    Linux Shell 编程
    Linux下压缩与解压
    rsync实现文件备份同步
    linux中ulimit作用
    3dmax卡通渲染插件pencil+渲染线框
    世嘉开发部部长:这3点能提升游戏留存率
    消息中间件 分布式
    高并发高性能
    你的系统如何支撑高并发
    分布式系统的阿喀琉斯之踵:数据一致性
  • 原文地址:https://www.cnblogs.com/ullio/p/14561631.html
Copyright © 2020-2023  润新知