• POJ 2723 Get Luffy Out


    POJ_2723

    一开始还是没有抓住2-SAT题目的核心,不会构图。

    其实2-SAT最重要的一点就是要找出0-1的关系,即一个东西要么选要么不选,或者要么选这个状态,要么选那个状态,这个物品就应是核心的变量。显然这个题目只有一个物品满足这一点——钥匙,对一把钥匙来讲,我们要么用它要么不用它。

    找到核心变量之后,剩下的工作就相对轻松了。首先,对于一对钥匙AB,我们可以得到这样的结论:如果选A,那么一定不选B,如果选B,那么一定不选A,于是就能够连两条边A->~BB->~A。其次,对于能够开一扇门的两把锁CD,我们可以得到这样的结论:如果不用CC锁,那么就必然要用DD锁,如果不用DD锁,那么就一定要用CC锁,于是我们又能够连两条边。

    在求解开门数量的时候,我们可以二分枚举开门的数量,然后去找是否存在表示一把钥匙0-1状态的两个点在同一个强连通分量中,也就是去推导在当前开门数量下是否会产生矛盾(即我们既要用这把钥匙同时这把钥匙又不能用)即可。

    #include<stdio.h>
    #include<string.h>
    #define MAXN 6000
    #define MAXM 8000
    int first[MAXN], next[MAXM], v[MAXM], N, M;
    int dfn[MAXN], low[MAXN], cnt, s[MAXN], top, ins[MAXN];
    int color[MAXN], col;
    int key1[MAXN], key2[MAXN], door1[MAXN], door2[MAXN];
    int init()
    {
    int i;
    scanf("%d%d", &N, &M);
    if(!N && !M)
    return 0;
    for(i = 0; i < N; i ++)
    scanf("%d%d", &key1[i], &key2[i]);
    for(i = 0; i < M; i ++)
    scanf("%d%d", &door1[i], &door2[i]);
    return 1;
    }
    void tarjan(int u)
    {
    int e;
    dfn[u] = low[u] = ++ cnt;
    for(e = first[u]; e != -1; e = next[e])
    {
    if(!dfn[v[e]])
    {
    s[top ++] = v[e];
    ins[v[e]] = 1;
    tarjan(v[e]);
    if(low[v[e]] < low[u])
    low[u] = low[v[e]];
    }
    else if(ins[v[e]] && dfn[v[e]] < low[u])
    low[u] = dfn[v[e]];
    }
    if(low[u] == dfn[u])
    {
    for(s[top] = -1; s[top] != u;)
    {
    top --;
    ins[s[top]] = 0;
    color[s[top]] = col;
    }
    col ++;
    }
    }
    int com(int mid)
    {
    int i, j, k, u, e;
    memset(first, -1, sizeof(first));
    e = 0;
    for(i = 0; i < N; i ++)
    {
    v[e] = 2 * key2[i];
    u = 2 * key1[i] + 1;
    next[e] = first[u];
    first[u] = e;
    e ++;

    v[e] = 2 * key1[i];
    u = 2 * key2[i] + 1;
    next[e] = first[u];
    first[u] = e;
    e ++;
    }
    for(i = 0; i < mid; i ++)
    {
    v[e] = 2 * door2[i] + 1;
    u = 2 * door1[i];
    next[e] = first[u];
    first[u] = e;
    e ++;

    v[e] = 2 * door1[i] + 1;
    u = 2 * door2[i];
    next[e] = first[u];
    first[u] = e;
    e ++;
    }
    cnt = top = col = 0;
    memset(dfn, 0, sizeof(dfn));
    memset(ins, 0, sizeof(ins));
    for(i = 0; i < 2 * N; i ++)
    if(!dfn[i])
    {
    s[top ++] = i;
    ins[i] = 1;
    tarjan(i);
    }
    for(i = 0; i < 2 * N; i ++)
    if(color[i] == color[i ^ 1])
    return 0;
    return 1;
    }
    int main()
    {
    int max, mid, min;
    while(init())
    {
    min = 0;
    max = M + 1;
    for(;;)
    {
    mid = (max + min) / 2;
    if(mid == min)
    break;
    if(com(mid))
    min = mid;
    else
    max = mid;
    }
    printf("%d\n", mid);
    }
    return 0;
    }


  • 相关阅读:
    泛型
    多播委托
    匿名方法
    委托
    正则表达式
    压缩和解压,文件读取练习
    Vue样式绑定
    Vue跑马灯
    Vue中的v-for遍历循环
    Vue框架
  • 原文地址:https://www.cnblogs.com/staginner/p/2198510.html
Copyright © 2020-2023  润新知