• poj3648 2-sat


    题意:
          一对夫妻结婚,请来了n对夫妻,所有人坐在同一张桌子上吃饭,这张桌子是长方形的可以坐两排人,有如下限制
    (1) 新娘和新郎不做同一侧。
    (2) 每对来的夫妻也不能坐在同一侧。 
    (3) 有一些人有暧昧关系(男女,男男,或者女女),有暧昧关系的两

    个人不可以同时坐在新娘对面。


    输出一组可行解,输出的是坐在新娘对面的人。


    思路:

         根据限制关系,而且还是二选一,显然这个是2sat,对于每个人,都拆成两个点,一个是a表示坐在新娘这一侧,另一个是~a表示坐在新郎这一侧,则对于任何有暧昧关系的,要么一边坐一个,要不同时坐在新娘这一侧,则只要他们两个中至少有一个1就行了,建图是这样 ~a -> b ,~b -> a,对于每一对,他们不能坐在同一侧则不能相同,建图是 a -> ~b ,b -> ~a ,~a ->b ,~b -> a ,还有就是新娘必须坐在新娘这侧,直接 ~a -> a.


    #include<stdio.h>
    #include<string.h>
    #include<stack>
    
    #define N_node 5000
    #define N_edge 100000
    #define R 1
    #define B 2
    
    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] ,Col[N_node];
    stack<int>st ,stt;
    
    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) ,stt.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 solve(int n)
    {
         memset(mark ,0 ,sizeof(mark));
         while(!st.empty()) st.pop();
         while(!stt.empty()) stt.pop();
         for(int i = 0 ;i < 4 * n ;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);
         }
         for(int i = 0 ;i < n * 4 ;i += 2)
         if(Belong[i] == Belong[i^1]) return 0;
         return 1;
    }
    
    int main ()
    {
        int i ,n ,m ,a ,b;
        char c1 ,c2;
        while(~scanf("%d %d" ,&n ,&m) && n + m)
        {
            memset(list1 ,0 ,sizeof(list1));
            memset(list2 ,0 ,sizeof(list2)) ,tot = 1;
            for(i = 1 ;i <= m ;i ++)
            {
               scanf("%d%c%d%c" ,&a ,&c1 ,&b ,&c2);
               a = a * 2 + (c1 == 'h' ? 1 : 0);
               b = b * 2 + (c2 == 'h' ? 1 : 0);
               add(a * 2 + 1 ,b * 2);
               add(b * 2 + 1 ,a * 2);
            } 
            for(i = 0 ;i < n ;i ++)
            {
               a = i * 2 ,b = i * 2 + 1;
               add(a * 2 + 1 ,b * 2) ,add(b * 2 + 1 ,a * 2);
               add(a * 2 ,b * 2 + 1) ,add(b * 2 ,a * 2 + 1);
            }
            add(1 ,0);
            if(!solve(n))
            {
                printf("bad luck
    ");
                continue;
            }
            memset(Col ,0 ,sizeof(Col));
            while(!stt.empty())
            {
               i = stt.top() ,stt.pop();
               if(Col[i]) continue;
               Col[i] = B ,Col[i^1] = R;
            }
            int mk = 0;
            for(i = 4 ;i < n * 4 ;i += 2)
            {       
                if(Col[i] == B) continue;
                if(mk) printf(" ");mk = 1;
                printf("%d" ,i / 4);
                i % 4 > 1 ? printf("h") : printf("w");
            }
            puts("");
        }
        return 0;
    }

  • 相关阅读:
    190822——喜欢
    190821——彼岸无岸
    190820——随笔
    BLE——协议层次结构
    190817——肖申克的救赎
    190818——人
    190819——皖北部分村落的变迁史
    【转】vfork 和 fork的区别
    C语言文件操作
    【makefile】symbol <函数> : can't resolve symbol 问题分析
  • 原文地址:https://www.cnblogs.com/csnd/p/12063000.html
Copyright © 2020-2023  润新知