【算法练习】HDU - 1816 Get Luffy Out *(2-SAT)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/pengwill97/article/details/82082011

题意

题解

直接把POJ的那道题交上去就过了。
先说一下POJ那道题的做法。
二分能开的门个数,然后判断是是否合法。由于开门的是有先后顺序的,前边的没开,后边的门也开不了,所以在二分一个开门个数的时候,要限制图中某些边是否能选中。这个在对门建图的时候,对边加一个id,每次二分tarjan时,判断一下边的id是否小于当前二分的id,若小于等于的话,就表示这条边是在二分位置之间的限制关系,可以走,否则不可以走。
对于门和钥匙分别建图。

  1. 对于钥匙来说,选a不能选b,选b不能选a。
  2. 对于们来说,若a不选择必选b,若b不选择必选a。

他们之间逻辑是不同的。

代码

#include<bits/stdc++.h>
using namespace std;
typedef double db;
typedef long long ll;
typedef unsigned long long ull;
const int nmax = 1e6+7;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const ull p = 67;
const ull MOD = 1610612741;
int head[nmax], tot;
struct edge {
    int to, nxt, id;
}e[nmax<<1];
int low[10005], dfn[10005], color[10005], ss[10005], st, dfs_clock, scc;
bool instack[10005];
int n , m;
void add_edge(int u, int v, int id) {
    e[tot].to = v;
    e[tot].nxt = head[u];
    e[tot].id = id;
    head[u] = tot++;
}
void init() {
    memset(head ,-1, sizeof head);
    tot = 0;
}
void tarjan(int u, int x) {
    low[u] = dfn[u] = ++dfs_clock;
    ss[st++] = u ;
    instack[u] = true;
    for(int i = head[u]; i != -1; i = e[i].nxt) {
        int v = e[i].to;
        if(e[i].id > x)
            continue;
        if(!dfn[v]) {
            tarjan(v, x);
            low[u] = min (low[u], low[v]);
        } else if(instack[v]) {
            low[u] = min(low[u], dfn[v]);
        }
    }
    if(low[u] == dfn[u]) {
        scc ++;
        int tmp = 0;
        while(1) {
            tmp = ss[--st];
            color[tmp] = scc;
            instack[tmp] = false;
            if(tmp == u)
                break;
        }
    }
}
bool check(int x) {
    memset(low, 0, sizeof low);
    memset(dfn, 0, sizeof dfn);
    memset(color, 0, sizeof color);
    st = dfs_clock = scc = 0;
    for(int i = 1; i <= 2 * n; ++i) {
        if(!dfn[i])
            tarjan(i, x);
    }
    for(int i = 1; i <= n; ++i) {
        if(color[i] != 0 && color[i+n] != 0 && color[i] == color[i+n])
            return false;
    }
    return true;
}
int main(){
    while(scanf("%d %d", &n, &m) != EOF) {
        if(n == 0 && m == 0)
            break;
        init();
        int u , v;
        for(int i = 1; i <= n; ++i) {
            scanf("%d %d", &u, &v);
            u ++;
            v ++;
            add_edge(u, v + n, -1);
            add_edge(v, u + n, -1);
        }
        for(int i = 1; i <= m; ++i) {
            scanf("%d %d", &u, &v);
            u ++;
            v ++;
            add_edge(v + n, u, i);
            add_edge(u + n, v, i);
        }
        if(n == 0) {
            printf("0\n");
            continue;
        }
        int ans = 0, l = 0 , r = m;
        while(l <= r) {
            int mid = (l + r) >>1;
            if(check(mid)) {
                ans = mid;
                l = mid + 1;
            }else r = mid - 1;
        }
        printf("%d\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/pengwill97/article/details/82082011
今日推荐