• 有向图博弈+出度的结合 Codeforces Round #406 (Div. 2) C


    http://codeforces.com/contest/787/problem/C

    题目大意:有一个长度为n的环,第1个位置是黑洞,其他都是星球。已知在星球上(不含第一个黑洞)有一位神。有两个人,每个人有一个集合的数字,两人进行游戏,每人每轮可以让神从一个星球向后移动x位(x为目前两个人所拥有的集合中的一个任意数字,数字可以重复选)。请求出神在2~n的每一个位置上时,两人分别先手的输赢情况,先手胜利输出WIN,先手必败输出LOOS,会无限循环输出LOOP。

    思路:经典的有向图博弈(可惜我不会TAT)。

    假定范围是[0,n-1],那么定义dp(i, j)表示是第i个人,在第j个位置先手的情况(三种情况,loop,lose,win)。然后我们知道了在dp[0][0] = dp[1][0] = lose是必败的,所以我们反向回去推即可。然后反向推是利用bfs进行的。

    ①因为对于某个点,如果是必败态,那么他之间的状态都是必胜的

    ②如果当前点是必胜态,那么他之前的状态中必然有一个点是必败的。那么也就是说,那么必败的点的出度必然为0。

    为什么出度为0就是必败呢。因为对于目前的这个状态,他可以往前面转移,假定他有k种转移方法,那么他的出度就是k。那么,我们定义目前的状态是必胜态,那么他转移出去的必然都是必败态。所以,假如说那个是必胜态,那么我们就对k--。如果k是0了,那么表示转移出去的只有必胜态了,所以当前的状态只能是必败态

    感觉理解起来还是简单的^0^,开心

    //看看会不会爆int!数组会不会少了一维!
    //取物问题一定要小心先手胜利的条件
    #include <bits/stdc++.h>
    using namespace std;
    #pragma comment(linker,"/STACK:102400000,102400000")
    #define LL long long
    #define ALL(a) a.begin(), a.end()
    #define pb push_back
    #define mk make_pair
    #define fi first
    #define se second
    #define haha printf("haha
    ")
    const int maxn = 7000 + 5;
    int dp[2][maxn];
    int cnt[2][maxn];
    vector<int> ve[2];
    int n, k;
    
    void solve(){
        queue<pair<int ,int> > que;
        memset(dp, -1, sizeof(dp));
        dp[0][0] = 0, dp[1][0] = 0;///0为必败,1为必胜
        que.push(mk(0, 0)); que.push(mk(1, 0));
        while (!que.empty()){
            pair<int, int> p = que.front(); que.pop();
            int x = p.fi, y = p.se;
            if (dp[x][y] == 0){
                for (int i = 0; i < ve[x ^ 1].size(); i++){
                    int nx = x ^ 1, ny = (p.se + n - ve[x^1][i]) % n;
                    if (dp[nx][ny] == -1){
                        dp[nx][ny] = 1; que.push(mk(nx, ny));
                    }
                }
            }
            else if (dp[x][y] == 1){
                for (int i = 0; i < ve[x ^ 1].size(); i++){
                    int nx = x ^ 1, ny = (p.se + n - ve[x^1][i]) % n;
                    cnt[nx][ny]--;
                    if (cnt[nx][ny] == 0 && dp[nx][ny] == -1){
                        dp[nx][ny] = 0; que.push(mk(nx, ny));
                    }
                }
            }
        }
        for (int i = 0; i < 2; i++){
            for (int j = 1; j < n; j++){
                if (dp[i][j] == -1) printf("Loop ");
                else if (dp[i][j] == 0) printf("Lose ");
                else printf("Win ");
            }
            cout << endl;
        }
    }
    
    int main(){
        cin >> n >> k;
        for (int i = 1; i < n; i++) cnt[0][i] = k;
        while (k--){
            int u; cin >> u;
            ve[0].pb(u);
        }
        cin >> k;
        for (int i = 1; i < n; i++) cnt[1][i] = k;
        while (k--){
            int u; cin >> u;
            ve[1].pb(u);
        }
        solve();
        return 0;
    }
    View Code
  • 相关阅读:
    Python 字典方法(.get .item)
    Python格式化输出
    R sprintf函数
    r 中sub() gsub()等匹配与替换函数
    R read.csv数据框
    C#中使用ref、out、params例子
    C#中的三种委托方式:Func委托,Action委托,Predicate委托
    tfs强制撤销解锁命令
    Json序列化与反序列化
    XPath语法在C#中使用XPath示例第二讲
  • 原文地址:https://www.cnblogs.com/heimao5027/p/6663505.html
Copyright © 2020-2023  润新知