zoukankan      html  css  js  c++  java
  • 「NOI2017」游戏

    传送门

    不难发现题目可以转化成 ( ext{2-SAT}) 模型。

    对于 ( ext{A、B、C}) 三种场地,它们都只有两种可能的场地选择,麻烦的是 ( ext{X}) 场地,我们发现它有三种选择,而我们是不可能做 ( ext{3-SAT}) 的(这根本做不了嘛。

    对于这种情况我们一般是先 ( ext{DFS}) ,把三种选择变成两种选择,然后再一起跑 ( ext{2-SAT})

    我们发现 ( ext{X}) 场地的数量最多是 (8) ,那么我们就可以直接枚举每一个 ( ext{X}) ,把他分别作为 ( ext{A、B、C}) 然后根据限制条件建图跑 ( ext{2-SAT}),连边方式和输出方案应该都比较好想,就不多说了(可以结合代码理解)。

    但是我们发现 (3^8=6561) ,再乘一个 (10^5) 级别的 (n) ,这显然是过不了的。

    怎么办呢?我们在 ( ext{DFS}) 时其实可以做到 (2^8),我们只需要枚举 ( ext{X} o ext{A}, ext{X} o ext{B}) 两种,因为这样就可以覆盖 ( ext{X}) 放三种不同赛车的情况了。

    参考代码:

    #include <algorithm>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    using namespace std;
    
    template < class T > void read(T& s) {
        s = 0; int f = 0; char c = getchar();
        while ('0' > c || c > '9') f |= c == '-', c = getchar();
        while ('0' <= c && c <= '9') s = s * 10 + c - 48, c = getchar();
        s = f ? -s : s;
    }
    
    const int _ = 2e5 + 5;
    
    int tot, head[_]; struct Edge { int v, nxt; } edge[_];
    void Add_edge(int u, int v) { edge[++tot] = (Edge) { v, head[u] }, head[u] = tot; }
    
    int n, d, m, a[_], ch[2][_], id[10];
    struct node { int u, hu, v, hv; } t[_];
    int num, dfn[_], low[_], col, co[_], top, stk[_];
    
    void tarjan(int u) {
        dfn[u] = low[u] = ++num, stk[++top] = u;
        for (int i = head[u]; i; i = edge[i].nxt) {
            int v = edge[i].v;
            if (!dfn[v])
                tarjan(v), low[u] = min(low[u], low[v]);
            else
                if (!co[v]) low[u] = min(low[u], dfn[v]);
        }
        if (dfn[u] == low[u]) {
            ++col;
            do co[stk[top]] = col;
            while (stk[top--] != u);
        }
    }
    
    void init() {
        tot = num = col = top = 0;
        memset(head, 0, sizeof head);
        memset(dfn, 0, sizeof dfn);
        memset(co, 0, sizeof co);
    }
    
    void solve() {
        init();
        for (int i = 1; i <= m; ++i) {
            int u = t[i].u, hu = t[i].u + t[i].hu * n;
            int v = t[i].v, hv = t[i].v + t[i].hv * n;
            if (a[u] == t[i].hu) continue ;
            if (a[v] == t[i].hv)
                Add_edge(ch[ch[1][u] == hu][u], ch[ch[1][u] != hu][u]);
            else {
                Add_edge(hu, hv);
                Add_edge(ch[ch[1][v] != hv][v], ch[ch[1][u] != hu][u]);
            }
        }
        for (int i = 1; i <= n; ++i) {
            if (!dfn[ch[0][i]]) tarjan(ch[0][i]);
            if (!dfn[ch[1][i]]) tarjan(ch[1][i]);
        }
        for (int i = 1; i <= n; ++i)
            if (co[ch[0][i]] == co[ch[1][i]]) return ;
        for (int i = 1; i <= n; ++i) {
            if (co[ch[0][i]] < co[ch[1][i]])
                printf("%c", (ch[0][i] - i) / n + 'A');
            else
                printf("%c", (ch[1][i] - i) / n + 'A');
        }
        exit(0);
    }
    
    void dfs(int x) {
        if (x == d + 1) return solve();
        int i = id[x];
        a[i] = 0, ch[0][i] = i + n, ch[1][i] = i + 2 * n, dfs(x + 1);
        a[i] = 1, ch[0][i] = i, ch[1][i] = i + 2 * n, dfs(x + 1);
    }
    
    int main() {
    #ifndef ONLINE_JUDGE
        freopen("cpp.in", "r", stdin), freopen("cpp.out", "w", stdout);
    #endif
        read(n), read(d);
        char S[_]; scanf("%s", S + 1);
        for (int i = 1; i <= n; ++i) {
            if (S[i] == 'a') a[i] = 0, ch[0][i] = i + n, ch[1][i] = i + 2 * n;
            if (S[i] == 'b') a[i] = 1, ch[0][i] = i, ch[1][i] = i + 2 * n;
            if (S[i] == 'c') a[i] = 2, ch[0][i] = i, ch[1][i] = i + n;
            if (S[i] == 'x') id[++id[0]] = i;
        }
        read(m);
        for (int u, hu, v, hv, i = 1; i <= m; ++i) {
            read(u), hu = getchar() - 'A';
            read(v), hv = getchar() - 'A';
            t[i] = (node) { u, hu, v, hv };
        }
        dfs(1);
        printf("-1");
        return 0;
    }
    
  • 相关阅读:
    添加GDataXMLNODE.h和.m的方法
    NSPredicate的用法
    oc正则表达式基本语法(二)
    洛谷3931 [洛谷八连测] 一道难题
    洛谷2024 食物链 并查集
    洛谷1005 【NOIP2007】矩阵取数游戏
    洛谷3927 [洛谷八连测] 一道中档题
    洛谷1113 杂务
    洛谷1019 单词接龙 字符串dfs
    洛谷1414 又是毕业季II
  • 原文地址:https://www.cnblogs.com/zsbzsb/p/13052188.html
Copyright © 2011-2022 走看看