zoukankan      html  css  js  c++  java
  • POJ2723-Get Luffy Out(2-SAT)

    题意:有m扇门,每个门上有两把锁,打开任意一个锁都可以打开这扇门。门要按顺序一个一个打开。

    现在有n对不同的钥匙,每对钥匙只能用其中一个,问最多能打开多少门。

    题解:对钥匙建图,门是限制条件来建边。每加一扇门就多一个限制条件,直到2-sat不满足为止。当然二分会更快一些。有一个trick就是门上的两把锁相同的情况,也是就这个钥匙是必须用的,建边特殊考虑。

    PS:我到底要错多少次才能长记性数组开足够大!!!以后WA了看数组!!TLE了看数组!!RE了看数组!!!

    #include <algorithm>
    #include <cstring>
    #include <cstdio>
    using namespace std;
    
    typedef long long ll;
    
    const int N = 1<<12;
    const int M = 1<<13;
    
    struct Edge {
        int from, to, next;
    } edge[M];
    int head[N];
    int cntE;
    void addedge(int u, int v) {
        edge[cntE].from = u; edge[cntE].to = v; edge[cntE].next = head[u]; head[u] = cntE++;
    }
    
    int dfn[N], low[N], idx;
    int stk[N], top;
    int in[N];
    int kind[N], cnt;
    
    void tarjan(int u)
    {
        dfn[u] = low[u] = ++idx;
        in[u] = true;
        stk[++top] = u;
        for (int i = head[u]; i != -1; i = edge[i].next) {
            int v = edge[i].to;
            if (!dfn[v]) tarjan(v), low[u] = min(low[u], low[v]);
            else if (in[v]) low[u] = min(low[u], dfn[v]);
        }
        if (low[u] == dfn[u]) {
            ++cnt;
            while (1) {
                int v = stk[top--]; kind[v] = cnt; in[v] = false;
                if (v == u) break;
            }
        }
    }
    
    bool sat(int n) // 序号从0开始
    {
        for (int i = 0; i < 2*n; ++i) if (!dfn[i]) tarjan(i);
        for (int i = 0; i < 2*n; i += 2) {
            if (kind[i] == kind[i^1]) return false;
        }
        return true;
    }
    
    void init() {
        memset(dfn, 0, sizeof dfn);
        memset(in, false, sizeof in);
        idx = top = cnt = 0;
    }
    int key[M];
    int a[N], b[N];
    int main()
    {
        int n, m;
        int u, v;
        while (~scanf("%d%d", &n, &m) && n) {
            cntE = 0; memset(head, -1, sizeof head);
            for (int i = 0; i < n; ++i) {
                scanf("%d%d", &u, &v);
                key[u] = 2*i; key[v] = 2*i+1;
            }
    
            for (int i = 0; i < m; ++i) {
                scanf("%d%d", a+i, b+i);
            }
            for (int i = 0; i < m; ++i) {
                if (a[i] == b[i]) addedge(key[ a[i] ]^1, key[ a[i] ]);
                else {
                    addedge(key[ a[i] ]^1, key[ b[i] ]);
                    addedge(key[ b[i] ]^1, key[ a[i] ]);
                }
                init();
                if (!sat(n)) {
                    printf("%d
    ", i);
                    break;
                }
                if (i == m-1) {
                    printf("%d
    ", m);
                }
            }
        }
    
        return 0;
    }
    
    /**
    3 3
    1 2 3 4 5 6
    3 3 2 2 4 4
    
    3 3
    0 1 2 3 4 5
    0 2 1 1 3 3
    
    **/
  • 相关阅读:
    Centos 下查看服务器CPU的信息
    网速的一些知识整理
    如何复制文件夹里面的全部内容? 在pc上
    DataGridView中CellClick的使用,选中一行触发的动作可以在这个方法里执行
    C# 文件的压缩与解压缩
    C#调用Exe 及 有参数的
    oracle提示 ORA12154: TNS: 无法解析指定的连接标识符 OCIEnvCreate 失败, 返回代码为1,但错误消息文本不可用
    C# 导出wps配置服务器 注意事项
    C# FTP 操作类
    组件服务问题
  • 原文地址:https://www.cnblogs.com/wenruo/p/5888287.html
Copyright © 2011-2022 走看看