zoukankan      html  css  js  c++  java
  • Go Deeper(2010成都现场赛题)(2-sat)

    G - Go Deeper
    Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu

    Description

    Here is a procedure's pseudocode:

     
    	   go(int dep, int n, int m)  
    	   begin  
    	      output the value of dep. 
    	      if dep < m and x[a[dep]] + x[b[dep]] != c[dep] then go(dep + 1, n, m)
    	   end 
    	 

    In this code n is an integer. abc and x are 4 arrays of integers. The index of array always starts from 0. Array a and b consist of non-negative integers smaller than n. Array x consists of only 0 and 1. Array c consists of only 0, 1 and 2. The lengths of array ab and c are mwhile the length of array x is n.

    Given the elements of array ab, and c, when we call the procedure go(0, n , m) what is the maximal possible value does the procedure output?

    Input

    There are multiple test cases. The first line of input is an integer T (0 < T ≤ 100), indicating the number of test cases. Then T test cases follow. Each case starts with a line of 2 integers n and m (0 < n ≤ 200, 0 < m ≤ 10000). Then m lines of 3 integers follow. The i-th(1 ≤ i ≤m) line of them are ai-1 ,bi-1 and ci-1 (0 ≤ ai-1bi-1 < n, 0 ≤ ci-1 ≤ 2).

    Output

    For each test case, output the result in a single line.

    Sample Input

    3
    2 1
    0 1 0
    2 1
    0 0 0
    2 2
    0 1 0
    1 1 2
    
    

    Sample Output

    1
    1
    2

    题目大意:
     
    给定一些方程,x[]数组未知,求前面最多能够有多少方程x[a]+x[b]!=c能够被满足。
     其中 c=0,1,2
      x[]={0,1}
    相当于裸的2sat问题,加上二分
      
      强烈建议阅读 kuangbin大神对2-sat的总结:http://www.cnblogs.com/kuangbin/archive/2012/10/05/2712429.html

    总的来说,就是当 a or b 时 连接 a' -> b 与 b' -> a 的边,然后进行强连通判断是否出现 a 与 a' ...在同一个连通分量中,若在则不可能。

    建立数a的两个状态,即a与a',相当于x[a]=1 和 x[a']=0

    x[a]+x[b]!=0 => a or b => a'->b 且 a->b'
    x[a]+x[b]!=1 => (a and b) or (a' and b') == a or b' 且 a' or b => a'->b' 且 b->a 且 a->b 且 b'->a
    x[a]+x[b]!=2 => a' or b' => a->b' 且 a'->b

    按上面来建图判断即可

    #include<cstdio>
    #include<cstring>
    int e[50000],pd[50000],be[800],ne[50000],all;
    int dfn[800],low[800],instack[800],belong[800],stack[800],stak,curr,num;
    int a,b,c,n,m,l,r,mid,flag;
    void add(int x,int y,int p){
        e[++all]=y;
        pd[all]=p;
        ne[all]=be[x];
        be[x]=all;
    }
    void tarjan(int x){
        instack[x]=1;
        stack[++stak]=x;
        dfn[x]=low[x]=++curr;
        for(int j=be[x];j!=0;j=ne[j])
        if(pd[j]<=mid){
            if(!dfn[e[j]]){
                tarjan(e[j]);
                if(low[x]>low[e[j]]) low[x]=low[e[j]];
            }else if(instack[e[j]]&&low[x]>low[e[j]])
                low[x]=low[e[j]];
        }
        if(dfn[x]==low[x]){
            int j;
            ++num;
            do{
                j=stack[stak--];
                instack[j]=0;
                belong[j]=num;
            }while(j!=x);
        }
    }
    int solve(){
        curr=stak=num=0;
        memset(dfn,0,sizeof(dfn));
        memset(low,0,sizeof(low));
        memset(instack,0,sizeof(instack));
        for(int i=0;i<2*n;i++)
            if(!dfn[i]) tarjan(i);
        flag=0;
        for(int i=0;i<n;i++)
            if(belong[2*i]==belong[2*i+1]){
                flag=1;
                break;
            }
        return flag;
    }
    int main()
    {
        int tt;
        scanf("%d",&tt);
        while(tt--){
            scanf("%d%d",&n,&m);
            all=0;
            memset(e,0,sizeof(e));
            memset(be,0,sizeof(be));
            memset(ne,0,sizeof(ne));
            memset(pd,0,sizeof(pd));
            for(int i=0;i<m;i++){
                scanf("%d%d%d",&a,&b,&c);
                switch (c){
                case 0: add(2*a+1,2*b,i);
                        add(2*b+1,2*a,i);
                        break;
                case 1: add(2*a,2*b,i);
                        add(2*b+1,2*a+1,i);
                        add(2*b,2*a,i);
                        add(2*a+1,2*b+1,i);
                        break;
                case 2: add(2*a,2*b+1,i);
                        add(2*b,2*a+1,i);
                        break;
                }
            }
            l=0;r=m-1;
            while(l<r-1){
                mid=(l+r)/2;
                if(solve()) r=mid; else l=mid;
            }
            mid=r;
            if(!solve()) printf("%d
    ",r+1);
            else printf("%d
    ",l+1);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    leetcode 279. Perfect Squares
    leetcode 546. Remove Boxes
    leetcode 312. Burst Balloons
    leetcode 160. Intersection of Two Linked Lists
    leetcode 55. Jump Game
    剑指offer 滑动窗口的最大值
    剑指offer 剪绳子
    剑指offer 字符流中第一个不重复的字符
    leetcode 673. Number of Longest Increasing Subsequence
    leetcode 75. Sort Colors (荷兰三色旗问题)
  • 原文地址:https://www.cnblogs.com/Mathics/p/3866886.html
Copyright © 2011-2022 走看看