• 3495: PA2010 Riddle


    3495: PA2010 Riddle

    链接

    分析:

      每个点要么建首都,要么不建,并且一个点建了,会导致一些点不能建。所以可以考虑2-sat。

      但是如果在每个郡里两两连边,边数是n^2的。

      考虑用前缀优化。

      S[i]表示对于当前郡,前i个点中是否存在一个首都,A[i]表示i这个点是否建首都。

      1、那么有A[i]=1,则S[i]=1,同样有它的逆否命题:S[i]=0,则A[i]=0。

      2、根据前缀的性质有S[i-1]=1,则S[i]=1,逆否命题:S[i]=0,则S[i-1]=0。

      3、由于每个郡只能有一个首都,所以A[i]=1,则S[i-1]=0,逆否命题:S[i-1]=1,则A[i]=0。

      4、还有满足每条边两边至少一个首都,u=0,则v=1,逆否命题:v=0,则u=1

    代码:

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<iostream>
    #include<cmath>
    #include<cctype>
    #include<set>
    #include<queue>
    #include<vector>
    #include<map>
    using namespace std;
    typedef long long LL;
    
    inline int read() {
        int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
        for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
    }
    
    const int N = 4000005;
    struct Edge{ int to, nxt; } e[N << 1];
    int head[N], dfn[N], low[N], bel[N], sk[N], top, Index, tot, En;
    bool vis[N];
    
    inline void add_edge(int u,int v) {
        ++En; e[En].to = v, e[En].nxt = head[u]; head[u] = En;
    }
    void tarjan(int u) {
        low[u] = dfn[u] = ++Index;
        sk[++top] = u; vis[u] = 1;
        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]);
            }
            if (vis[v]) low[u] = min(low[u], dfn[v]);
        }
        if (low[u] == dfn[u]) {
            ++tot;
            do {
                vis[sk[top]] = 0;
                bel[sk[top]] = tot;
                top --;
            } while (sk[top + 1] != u);
        }
    }
    int main() {
        int n = read(), m = read(), k = read();
        for (int u, v, i = 1; i <= m; ++i) {
            u = read(), v = read();
            add_edge(u + n, v);add_edge(v + n, u);
        }
        for (int i = 1; i <= n; ++i) // A[i]=1,S[i]=1
            add_edge(i, i + 2 * n), add_edge(i + 3 * n, i + n);
        for (int cnt, now, last, i = 1; i <= k; ++i) {
            cnt = read(), last = read();
            for (int j = 2; j <= cnt; ++j) {
                now = read();
                add_edge(last + 2 * n, now + 2 * n);add_edge(now + 3 * n, last + 3 * n); // S[i-1]=1,S[i]=1
                add_edge(now, last + 3 * n); add_edge(last + 2 * n, now + n); // A[i]=1,S[i-1]=0
                last = now;
            }
        }
        for (int i = 1; i <= (n << 2); ++i) if (!dfn[i]) tarjan(i);
        for (int i = 1; i <= n; ++i) {
            if (bel[i] == bel[i + n] || bel[i + 2 * n] == bel[i + 3 * n]) {
                puts("NIE"); return 0; 
            }
        }
        puts("TAK");
        return 0;
    }
  • 相关阅读:
    Faster rcnn代码理解(2)
    Faster rcnn代码理解(1)
    BN讲解(转载)
    faster-rcnn
    编程修养
    人才盘点
    Source Insight 技巧总结
    使用DNSSCrypt解决DNS污染问题
    程序员的自我修养 学习笔记(5)
    闯红灯检测原理
  • 原文地址:https://www.cnblogs.com/mjtcn/p/10291738.html
Copyright © 2020-2023  润新知