zoukankan      html  css  js  c++  java
  • hdu4115 2sat

    题意:
          两个人玩剪刀石头布,他们玩了n把,给了你A这n把都出了什么,问你B能否会赢,其中A会限制B某些局数出的要相同,某些局数出的要不同,只要B满足他的限制,并且没没有输掉任何一把就算赢(没有输掉就是平或者赢)。

    思路:

          首先考虑下,对于每一步,我们知道A出了什么,那么也就知道B在这不可以出什么,比如A在这一步出了1 那么B可以出1,2。对于每一步B都有两种选择,并且在步于步之间有一些限制,两种选择,一些限制,显然2sat,把每一次可以出的两个看成一组,一个是a,一个是~a,对于每一种限制我们只要找出它的矛盾对就行了,矛盾对的建边遵循 x ,y矛盾则有add(x ,~y) ,add(y ,~x) ,要注意这里面的 x,~x是相对而言,x = ~x^1 同时 x^1 = ~x,建边的时候别糊涂就行了,总之这个题目应该是2算是sat的简单题目。


    #include<stdio.h>
    #include<string.h>
    #include<stack>
    
    #define N_node 20000 + 100
    #define N_edge 50000 + 500
    
    using namespace std;
    
    typedef struct
    {
       int to ,next;
    }STAR;
    
    STAR E1[N_edge] ,E2[N_edge];
    int list1[N_node] ,list2[N_node] ,tot;
    int Belong[N_node] ,cnt;
    int mark[N_node];
    int A[11000][2];
    stack<int>st;
    
    void add(int a ,int b)
    {
       E1[++tot].to = b;
       E1[tot].next = list1[a];
       list1[a] = tot;
       
       E2[tot].to = a;
       E2[tot].next = list2[b];
       list2[b] = tot;
    }
    
    void DFS1(int s)
    {
       mark[s] = 1;
       for(int k = list1[s] ;k ;k = E1[k].next)
       if(!mark[E1[k].to])DFS1(E1[k].to);
       st.push(s);
    }
    
    void DFS2(int s)
    {
       mark[s] = 1 ,Belong[s] = cnt;
       for(int k = list2[s] ;k ;k = E2[k].next)
       if(!mark[E2[k].to])DFS2(E2[k].to);
    }
    
    bool ok(int n)
    {
       memset(mark ,0 ,sizeof(mark));
       while(!st.empty()) st.pop();
       for(int i = 0 ;i < n * 2 ;i ++)
       if(!mark[i]) DFS1(i);
       memset(mark ,0 ,sizeof(mark));
       cnt = 0;
       while(!st.empty())
       {
          int xin = st.top();
          st.pop();
          if(mark[xin]) continue;
          cnt ++;
          DFS2(xin);
       }
       int mk = 0;
       for(int i = 0 ;i < n * 2 && !mk ;i += 2)
       if(Belong[i] == Belong[i^1]) mk = 1;
       return !mk;
    }
    
    int main ()
    {
       int t ,n ,m ,i ,a ,b ,c ,cas = 1;
       scanf("%d" ,&t);
       while(t--)
       {
          scanf("%d %d" ,&n ,&m);
          for(i = 1 ;i <= n ;i ++)
          {
             scanf("%d" ,&a);
             A[i][0] = a;
             A[i][1] = a % 3 + 1;
          }
          memset(list1 ,0 ,sizeof(list1));
          memset(list2 ,0 ,sizeof(list2));
          tot = 1;
          for(i = 1 ;i <= m ;i ++)
          {
             scanf("%d %d %d" ,&a ,&b ,&c);
             int x1 = a * 2 ,x2 = a * 2 + 1;
             int y1 = b * 2 ,y2 = b * 2 + 1;
             if(!c && A[a][0] != A[b][0] || c && A[a][0] == A[b][0])
             add(x1 ,y1^1) ,add(y1 ,x1^1);
             if(!c && A[a][0] != A[b][1] || c && A[a][0] == A[b][1])
             add(x1 ,y2^1) ,add(y2 ,x1^1);
             if(!c && A[a][1] != A[b][0] || c && A[a][1] == A[b][0])
             add(x2 ,y1^1) ,add(y1 ,x2^1);
             if(!c && A[a][1] != A[b][1] || c && A[a][1] == A[b][1])
             add(x2 ,y2^1) ,add(y2 ,x2^1);
          }
          printf("Case #%d: " ,cas ++);
          if(!ok(n)) puts("no");
          else puts("yes");
       }
       return 0;
    }
             
          

  • 相关阅读:
    SpringBoot自动装配原理解析
    面试官:你知道Spring中有哪些可以让我们扩展的地方么
    Spring事件监听机制
    Spring扩展点之Aware接口族
    程序员的进阶课-架构师之路(13)-B-树
    程序员的进阶课-架构师之路(12)-2-3-4树
    程序员的进阶课-架构师之路(11)-最容易理解的红黑树
    程序员的进阶课-架构师之路(10)-霍夫曼树
    程序员的进阶课-架构师之路(9)-平衡二叉树(AVL树)
    程序员的进阶课-架构师之路(8)-二叉树
  • 原文地址:https://www.cnblogs.com/csnd/p/12063006.html
Copyright © 2011-2022 走看看