• LG 题解 CF936B Sleepy Game


    题目传送

    更棒的阅读体验?

    Solution

    题意非常的简单,没啥可说的。

    先判断 Win 的情况:

    你考虑用 (f_{u,0/1}) 来表示走到 (u) 这个点走了偶(奇)步这个状态有没有出现过。

    对于边 ((u,v)),显然有转移方程:

    [f_{v,0} |= f_{u,1} ]

    [f_{v,1} |= f_{u,0} ]

    然后你在记录一个出度。

    这样的话,dfs 更新一遍,最后看一看出度为 (0) 的点走了奇步这个状态存在没有。

    题目要求输出路径,这个操作比较平凡,记录一个 (pre) 递归输出即可。

    再考虑判断 Draw 的情况。

    我们要注意的是 Draw 的优先级比 Lose 要高。估计就我一个人没看出来。

    所以在不能走奇步停止的情况下,能进圈就进圈。

    一开始我的想法是用 tarjan 缩点,建出新图,接着从 (s) 所在点 dfs,看看经过的路径有没有环。但是我写挂了。

    考虑另外一种更简单的做法,只从 (s)tarjan,记录下缩的最大环。

    直接根据这个最大环的大小来判断就可以了。

    其他问题看代码。

    Code

    /*
    Work by: Suzt_ilymics
    Problem: 不知名屑题
    Knowledge: 垃圾算法
    Time: O(能过)
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #define LL long long
    #define orz cout<<"lkp AK IOI!"<<endl
    
    using namespace std;
    const int MAXN = 2e5+5;
    const int INF = 1e9+7;
    const int mod = 1e9+7;
    
    struct edge {
        int from, to, nxt;
    }e[MAXN << 1];
    int head[MAXN], num_edge = 1;
    
    int n, m, s, cnt = 0, t = 0, Max = 0;
    int od[MAXN];
    int pre[MAXN][2];
    int dfn[MAXN], low[MAXN], siz[MAXN], num[MAXN], stc[MAXN], sc = 0;
    bool f[MAXN][2], vis[MAXN];
    
    int read(){
        int s = 0, f = 0;
        char ch = getchar();
        while(!isdigit(ch))  f |= (ch == '-'), ch = getchar();
        while(isdigit(ch)) s = (s << 1) + (s << 3) + ch - '0' , ch = getchar();
        return f ? -s : s;
    }
    
    void add_edge(int from, int to) { e[++num_edge] = (edge){from, to, head[from]}, head[from] = num_edge; }
    
    void tarjan(int u) {
        dfn[u] = low[u] = ++cnt, vis[u] = true, stc[++sc] = u;
        for(int i = head[u]; i; i = e[i].nxt) {
            int v = e[i].to;
            if(!dfn[v]) {
                tarjan(v);
                low[u] = min(low[u], low[v]);
            } else if(vis[v]) {
                low[u] = min(low[u], dfn[v]);
            }
        }
        if(dfn[u] == low[u]) {
            int cnt = 0;
            int pre = stc[sc--]; vis[pre] = false;
            ++cnt;
            while(pre != u) {
                pre = stc[sc--], vis[pre] = false;
                ++cnt;
            }
            Max = max(Max, cnt);
        }
    }
    
    void Dfs(int u) {
        for(int i = head[u]; i; i = e[i].nxt) {
            int v = e[i].to, flag = false;
            if(!f[v][0] && f[u][1]) f[v][0] = true, flag = true, pre[v][0] = u;
            if(!f[v][1] && f[u][0]) f[v][1] = true, flag = true, pre[v][1] = u;
            if(flag) Dfs(v);
        }
    }
    
    void Print(int u, int p) {
        if(pre[u][p]) Print(pre[u][p], p^1);
        printf("%d ", u);
    }
    
    int main()
    {
    	n = read(), m = read();
    	for(int i = 1; i <= n; ++i) {
    	    int k = read();
    	    for(int j = 1, v; j <= k; ++j) {
    	        v = read();
    	        add_edge(i, v);
    	        od[i]++;
            }
        }
        s = read();
        f[s][0] = true;
        Dfs(s);
        bool flag = false;
        for(int i = 1; i <= n; ++i) {
            if(!od[i] && f[i][1]) {
                puts("Win");
                Print(i, 1);
                puts("");
                return 0;
            }
        }
        tarjan(s);
        if(Max > 1) puts("Draw");
        else puts("Lose");
        return 0;
    }
    
    
  • 相关阅读:
    多次drawRect,显示重叠,需要设置背景颜色
    WPF Combobox样式
    判断Window在哪个屏幕
    php 学习日志- 变量作用域
    C# Form.Close 的释放问题
    个人博客作业三:微软小娜APP的案例分析
    嵌入式软件设计第12次实验报告
    嵌入式软件设计第11次实验报告
    嵌入式软件设计第10次实验报告
    嵌入式软件设计第9次实验报告
  • 原文地址:https://www.cnblogs.com/Silymtics/p/solution-CF936B.html
Copyright © 2020-2023  润新知