zoukankan      html  css  js  c++  java
  • HDU 3715 Go Deeper

    HDU_3715

         我的第二个2-SAT的题目,^_^。整体的思路是二分深度,然后观察当前深度下是否能够推出矛盾。

    对于任意一个x[]只有01两种取值,并且只能为其中一种,为了便于分析,我们不妨设a[dep]的值为i,设b[dep]的值为j,设c[dep]的值为k2*i这个点代表x[i]02*i+1这个点代表x[i]1

    k一共有012三种取值,我们不妨分情况讨论一下x[]需要满足什么条件才可以达到下一个depth

    ①当k=2时,如果x[i]1,那么x[j]必然为0,于是需要连一条有向边2*i+1->j,同理,如果x[j]1,那么x[i]必然为0,于是需要连另一条有向边2*j+1->i

    ②当k=1时,如果x[i]0,则x[j]必然为0,如果x[i]1,则x[j]必然为1,同理如果x[j]0,则x[i]必然为0,如果x[j]1,则x[i]必然为1,连上对应的4条边即可。

    ③当k=0时,如果x[i]0,则x[j]必然为1,同理,如果x[j]0,则x[i]必然为1,连上对应的2条边即可。

         剩下的工作只要运用tarjan算法求强连通分量、缩点,然后判断是否有有一对数2*i2*i+1在一个强连通分量内(即能否推出矛盾——x[i]是必须为0同时又必须为1)即可。

    #include<stdio.h>
    #include<string.h>
    #define MAXD 410
    #define MAXM 40010
    int a[MAXM], b[MAXM], c[MAXM], n, m;
    int first[MAXD], next[MAXM], v[MAXM];
    int dfn[MAXD], low[MAXD], cnt;
    int top, s[MAXD], ins[MAXD], color[MAXD], col;
    void init()
    {
    int i;
    scanf("%d%d", &n, &m);
    for(i = 0; i < m; i ++)
    scanf("%d%d%d", &a[i], &b[i], &c[i]);
    }
    void tarjan(int u)
    {
    int i, 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, e, x1, x2;
    memset(first, -1, sizeof(first));
    e = 0;
    for(i = 0; i < mid; i ++)
    {
    if(c[i] == 2)
    {
    x1 = 2 * a[i] + 1;
    x2 = 2 * b[i];
    v[e] = x2;
    next[e] = first[x1];
    first[x1] = e;
    e ++;

    x1 = 2 * a[i];
    x2 = 2 * b[i] + 1;
    v[e] = x1;
    next[e] = first[x2];
    first[x2] = e;
    e ++;
    }
    else if(c[i] == 1)
    {
    x1 = 2 * a[i];
    x2 = 2 * b[i];
    v[e] = x2;
    next[e] = first[x1];
    first[x1] = e;
    e ++;
    v[e] = x1;
    next[e] = first[x2];
    first[x2] = e;
    e ++;

    x1 = 2 * a[i] + 1;
    x2 = 2 * b[i] + 1;
    v[e] = x2;
    next[e] = first[x1];
    first[x1] = e;
    e ++;
    v[e] = x1;
    next[e] = first[x2];
    first[x2] = e;
    e ++;
    }
    else
    {
    x1 = 2 * a[i];
    x2 = 2 * b[i] + 1;
    v[e] = x2;
    next[e] = first[x1];
    first[x1] = e;
    e ++;

    x1 = 2 * a[i] + 1;
    x2 = 2 * b[i];
    v[e] = x1;
    next[e] = first[x2];
    first[x2] = e;
    e ++;
    }
    }
    cnt = top = col =0;
    memset(ins, 0, sizeof(ins));
    memset(dfn, 0, sizeof(dfn));
    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 i, j, k, t, min, max, mid;
    scanf("%d", &t);
    while(t --)
    {
    init();
    max = m + 1;
    min = 0;
    for(;;)
    {
    mid = (max + min) / 2;
    if(mid == min)
    break;
    if(com(mid))
    min = mid;
    else
    max = mid;
    }
    printf("%d\n", mid);

    }
    return 0;
    }


  • 相关阅读:
    Java基础教程——模拟B/S结构的服务器
    Java基础教程——Socket编程
    Java基础教程——模拟浏览器发送请求
    Java基础教程——网络基础知识
    Java基础教程——线程通信
    Java基础教程——线程局部变量
    Java基础教程——线程同步
    Java基础教程——线程池
    Java基础教程——线程状态
    Java基础教程——多线程:创建线程
  • 原文地址:https://www.cnblogs.com/staginner/p/2198396.html
Copyright © 2011-2022 走看看