HDU 1816 Get Luffy Out *(2-SAT+二分)

来源:互联网 发布:流体力学分析软件 编辑:程序博客网 时间:2024/05/23 20:37

题目地址
题意:给你n串钥匙,每串钥匙有2把不同编号的钥匙,有一栋m层楼高的房子,每层有2个门,告诉你每个门要的钥匙,可能不同的门有相同的扼钥匙,但是一把钥匙打开了一个门,开完以后就会消失,问你最多能上几层。
思路:一看就是两判性的问题,两判性的问题解决方法就是2-SAT(说了不知道多少遍了),建图就老老实实建,判断一下他的限制关系:把每个钥匙拆成两个点(一个为选这把钥匙,一个为不选),然后二选一的话就把一串钥匙中的一把选与另一把的不选连边,然后开门的话就是开第一个门就不用开第二个门了,然后对应的钥匙选与不选连边就好了。

#include <iostream>#include <cstring>#include <string>#include <queue>#include <vector>#include <map>#include <set>#include <cmath>#include <cstdio>#include <algorithm>#include <iomanip>#define N 6010#define M 1000010//双倍#define LL __int64#define inf 0x3f3f3f3f#define lson l,mid,ans<<1#define rson mid+1,r,ans<<1|1#define getMid (l+r)>>1#define movel ans<<1#define mover ans<<1|1using namespace std;const LL mod = 1000000007;const double eps = 0.001;int n, m;int head[N], idx;struct node {    int to;    int next;}edge[M];struct cows {    int x, y;}key[N], lock[N];struct two_SAT {    int dfn[N], low[N];    int stack[N], top;    int belong[N], cnt, num;    bool vis[N];    void init() {        memset(head, -1, sizeof(head));        memset(belong, 0, sizeof(belong));        memset(dfn, 0, sizeof(dfn));        memset(vis, false, sizeof(vis));        num = cnt = 0;        top = 0;        idx = 0;    }    void addedge(int a, int b) {        edge[idx].to = b;        edge[idx].next = head[a];        head[a] = idx++;    }    void tarjin(int u) {//缩点        dfn[u] = low[u] = ++num;        vis[u] = true;        stack[top++] = u;        for (int i = head[u]; ~i; i = edge[i].next) {            int v = edge[i].to;            if (!dfn[v]) {                tarjin(v);                low[u] = min(low[u], low[v]);            }            else if (vis[v]) {                low[u] = min(low[u], dfn[v]);            }        }        if (dfn[u] == low[u]) {            while (true) {                int v = stack[--top];                vis[v] = false;                belong[v] = cnt;//标记联通分量belong                 if (u == v) break;            }            cnt++;        }    }    bool two_sat() {        for (int i = 0; i < 4 * n; i++) {//总点数              if (!dfn[i]) tarjin(i);        }        for (int i = 0; i < 4 * n; i += 2) {//遍历是不是会有一个人有2种可能            if (belong[i] == belong[i + 1]) {                return false;            }        }        return true;    }}sat;bool check(int num) {    sat.init();    for (int i = 0; i < n; i++) {//key*2为取这把钥匙 key*2+1为不取这把钥匙        int x = key[i].x * 2;        int y = key[i].y * 2 + 1;        sat.addedge(x, y);        sat.addedge(y ^ 1, x ^ 1);    }    for (int i = 0; i < num; i++) {//开第一个门就不用开第二个门了        int x = lock[i].x * 2 + 1;        int y = lock[i].y * 2;        sat.addedge(x, y);        sat.addedge(y ^ 1, x ^ 1);    }    return sat.two_sat();}int main() {    cin.sync_with_stdio(false);    while (cin >> n >> m) {        if (n == 0 && m == 0) {            break;        }        for (int i = 0; i < n; i++) {            cin >> key[i].x >> key[i].y;        }        for (int i = 0; i < m; i++) {            cin >> lock[i].x >> lock[i].y;        }        int l = 0, r = m;        int ans = -1;        while (l <= r) {            int mid = (l + r) / 2;            if (check(mid)) {                ans = mid;                l = mid + 1;            }            else                r = mid - 1;        }        cout << ans << endl;    }    return 0;}
原创粉丝点击