zoukankan      html  css  js  c++  java
  • poj 2723 Get Luffy Out 二分+2-sat

    题目链接

    给n个钥匙对, 每个钥匙对里有两个钥匙, 并且只能选择一个。
    有m扇门, 每个门上有两个锁, 只要打开其中一个就可以通往下一扇门。
    问你最多可以打开多少个门。


    对于每个钥匙对, 如果选择了其中一个钥匙, 那么另一个就不能选。 所以加边(a, b'), (b, a')。 对于每个门, 如果不打开其中一个锁, 那么另一个锁就一定要打开。 所以加边(a', b), (b', a)。 然后二分判断就可以了。
    #include <iostream>
    #include <vector>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <complex>
    #include <cmath>
    #include <map>
    #include <set>
    #include <string>
    #include <queue>
    #include <stack>
    #include <bitset>
    using namespace std;
    #define pb(x) push_back(x)
    #define ll long long
    #define mk(x, y) make_pair(x, y)
    #define lson l, m, rt<<1
    #define mem(a) memset(a, 0, sizeof(a))
    #define rson m+1, r, rt<<1|1
    #define mem1(a) memset(a, -1, sizeof(a))
    #define mem2(a) memset(a, 0x3f, sizeof(a))
    #define rep(i, n, a) for(int i = a; i<n; i++)
    #define fi first
    #define se second
    typedef complex <double> cmx;
    typedef pair<int, int> pll;
    const double PI = acos(-1.0);
    const double eps = 1e-8;
    const int mod = 1e9+7;
    const int inf = 1061109567;
    const int dir[][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} };
    const int maxe = 1e5;
    const int maxn = 5000;
    struct node
    {
        int nextt, to;
    }e[maxe];
    int n, m, num, cnt, top, deep, dfn[maxn], st[maxn], head[maxn], low[maxn], s[maxn], instack[maxn];
    pll a[maxn], b[maxn];
    void add(int u, int v) {
        e[num].to = v, e[num].nextt = head[u], head[u] = num++;
    }
    void tarjan(int u) {
        dfn[u] = low[u] = ++deep;
        instack[u] = 1;
        st[++top] = u;
        for(int i = head[u]; ~i; i = e[i].nextt) {
            int v = e[i].to;
            if(!dfn[v]) {
                tarjan(v);
                low[u] = min(low[u], low[v]);
            } else if (instack[v]) {
                low[u] = min(low[u], dfn[v]);
            }
        }
        if(dfn[u] == low[u]) {
            int v;
            cnt++;
            do {
                v = st[top--];
                instack[v] = 0;
                s[v] = cnt;
            } while(u != v);
        }
    }
    void init() {
        mem1(head);
        mem(instack);
        mem(dfn);
        mem(s);
        num = deep = top = cnt = 0;
    }
    int check(int x) {
        init();
        for(int i = 0; i < x; i++) {
            add(b[i].fi<<1|1, b[i].se<<1);
            add(b[i].se<<1|1, b[i].fi<<1);
        }
        for(int i = 0; i < n; i++) {
            add(a[i].fi<<1, a[i].se<<1|1);
            add(a[i].se<<1, a[i].fi<<1|1);
        }
        for(int i = 0; i < n<<2; i++) {
            if(!dfn[i])
                tarjan(i);
        }
        /*for(int i = 0; i < n<<1; i++)
            cout<<s[i]<<" ";
        cout<<endl;
        */for(int i = 0; i < 2*n; i++) {
            if(s[i<<1] == s[i<<1|1])
                return 0;
        }
        return 1;
    }
    int main()
    {
        while(~scanf("%d%d", &n, &m)) {
            if(n+m==0)
                break;
            for(int i = 0; i < n; i++) {
                scanf("%d%d", &a[i].fi, &a[i].se);
            }
            for(int i = 0; i < m; i++) {
                scanf("%d%d", &b[i].fi, &b[i].se);
            }
            int l = 0, r = m, ans;
            while(l <= r) {
                int mid = l+r>>1;
                if(check(mid)) {
                    l = mid+1;
                    ans = mid;
                } else {
                    r = mid-1;
                }
            }
            printf("%d
    ", ans);
        }
        return 0;
    }
    
    
  • 相关阅读:
    Android 编程下 Eclipse 恢复被删除的文件
    Android 编程下背景图片适配工具类
    Android 编程下 Managing Your App's Memory
    Android 编程下代码之(QQ消息列表滑动删除)
    Android 编程下 Canvas and Drawables
    Android 编程下 AlarmManager
    Android 编程下去除 ListView 上下边界蓝色或黄色阴影
    Java 编程下字符串的 16 位、32位 MD5 加密
    C#枚举类型和int类型相互转换
    MVC和普通三层架构的区别
  • 原文地址:https://www.cnblogs.com/yohaha/p/5403975.html
Copyright © 2011-2022 走看看