Poj P3648 Wedding___2-SAT

题目大意:

给出 N N 对 夫 妻 ,从 0 第 0 对 开 始 ,现在有一场宴会,可以坐两排, wife0 w i f e 0 必须做左边, husband0 h u s b a n d 0 必 须 坐 右 边 ,其他的夫妻不能坐在同一边,给出 M M 对通奸关系,有通奸关系的不能同时出现在wifte0的对面。
问是否存在一种可行安排方案,存在则输出可行方案的任意解。

分析:

这题真的坑啊..
题目可以转化成一道2-SAT模型,
我们设 iwifei i 表 示 w i f e i 坐 在 左 边
i+nhubandi i + n 表 示 h u b a n d i 坐 在 左 边
i+2nwifei i + 2 ∗ n 表 示 w i f e i 坐 在 右 边
i+n+2nhubandi i + n + 2 ∗ n 表 示 h u b a n d i 坐 在 右 边

显然 wife0 w i f e 0 必须要坐在左边, husband0 h u s b a n d 0 必须坐在右边,
所以连边 2n>0 2 ∗ n − > 0 n>3n n − > 3 ∗ n 保证
然后将所有的夫妻 wifei,husbandi w i f e i , h u s b a n d i ( i0 i ≠ 0 )连边
i>i+n+2n i − > i + n + 2 ∗ n i+n+2n>i i + n + 2 ∗ n − > i
i+2n>i+n i + 2 ∗ n − > i + n , i+n>i+2n i + n − > i + 2 ∗ n

注意同时坐在 wife0 w i f e 0 一边(左边)乱搞是允许的有点怪异
所以当其中一个坐右边时另一个必须坐右边,而一个坐左边时另一个怎么选都可以。
wifeiwifej w i f e i 跟 w i f e j 乱搞
连边 i+2n>j i + 2 ∗ n − > j j+2n>i j + 2 ∗ n − > i
wifeihusbandj w i f e i 跟 h u s b a n d j 乱搞
连边 i+2n>j+n i + 2 ∗ n − > j + n j+n+2n>i j + n + 2 ∗ n − > i
husbandihusbandj h u s b a n d i 跟 h u s b a n d j 乱搞
连边 i+n+2n>j+n i + n + 2 ∗ n − > j + n j+n+2n>i+n j + n + 2 ∗ n − > i + n
然后强连通分量判有无解,
缩点拓扑找方案即可
因为有多组数据,所以每次数组都要注意清零,
可是偏偏我用了个叫做vector的东东,
然后vector我只是clear了..而size并没有清零,所以拓扑的部分凉了..

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#define M 2000005  
#define N 2005

using namespace std; 

stack <int> st;
queue <int> Q;

struct Node { 
    int u, v, next; 
} a[M]; 
int Instack[N], Belong[N], dfn[N], low[N], Ls[N], cnt, tot, num, n, m; 
int Cp[N], Rd[N], Color[N]; 

void Addedge(int u, int v) { 
    cnt++;
    a[cnt].u = u;
    a[cnt].v = v; 
    a[cnt].next = Ls[u]; 
    Ls[u] = cnt; 
} 

void Clear_init() {
    for (int i = 0 ; i < 4 * n; i++)
         Ls[i] = Rd[i] = dfn[i] = low[i] = Color[i] = Instack[i] = 0;
    tot = num = cnt = 0;
}

void Tarjan(int u) { 
     dfn[u] = low[u] = ++num;  
     Instack[u] = 1;  
     st.push(u);  
     for (int i = Ls[u]; i; i = a[i].next) {   
          int v = a[i].v;  
          if (!dfn[v]){  
              Tarjan(v);  
              low[u] = min(low[u], low[v]);  
          }  
          else if (Instack[v]) low[u] = min(low[u], dfn[v]);  
     }   
     if (low[u] == dfn[u]) {  
          tot++;
          int rp;
          while ("rp++") {
                 rp = st.top(); 
                 st.pop();  
                 Instack[rp] = 0;  
                 Belong[rp] = tot;  
                 if (rp == u) break;
          } 
     }   
}  

void Top_sort() {
     vector <int> E[N];
     for (int i = 1; i <= cnt; i++) {
          int u =a[i].u, v = a[i].v;
          if (Belong[u] != Belong[v]) {
              E[Belong[v]].push_back(Belong[u]); 
              Rd[Belong[u]]++;
          }
       }

       for (int i = 1; i <= tot; i++)
            if (!Rd[i]) Q.push(i); 

       while (!Q.empty()) {
             int u = Q.front();
             Q.pop();
             if (!Color[u]) {
                      Color[u] = 1;      
                      Color[Cp[u]] = 2;
             }
             for (int i = 0; i < E[u].size(); i++){
                  Rd[E[u][i]]--;
                  if (!Rd[E[u][i]]) Q.push(E[u][i]);
             }
       }
}

bool solve_problem() { 
    for (int i = 0; i < 4 * n; i++) 
         if (!dfn[i]) Tarjan(i); 
    for (int i = 0; i < 2 * n; i++) { 
         if (Belong[i] == Belong[i + 2 * n]) return 0;  
         Cp[Belong[i]] = Belong[i + 2 * n];
         Cp[Belong[i + 2 * n]] = Belong[i]; 
    } 
    Top_sort(); 
    return 1; 
}

int main() {
    while (~scanf("%d %d", &n, &m)) {  
           if (!n && !m) break; 
           Clear_init();
           Addedge(2 * n, 0); 
           Addedge(n, 3 * n); 
           for (int i = 1; i < n; i++) { 
                Addedge(i, i + n + 2 * n); 
                Addedge(i + n + 2 * n, i);
                Addedge(i + 2 * n, i + n);
                Addedge(i + n, i + 2 * n);
           } 
           int x, y;
           char aa, bb;
           for (int i = 1; i <= m; i++) {
                scanf("%d%c %d%c", &x, &aa, &y, &bb); 
                if (aa == 'h') x = x + n; 
                if (bb == 'h') y = y + n; 
                Addedge(x + 2 * n, y); 
                Addedge(y + 2 * n, x); 
           }
           int count = 0;
           if (solve_problem()) { 
               for (int i = 1; i < n; i++) { 
                    if (Color[Belong[i]] == 1) { 
                        printf("%dw", i); 
                        count++; 
                        if (count != (n - 1)) printf(" "); 
                                         else printf("\n"); 
                    } else { 
                        printf("%dh", i); 
                        count++; 
                        if (count != (n - 1)) printf(" "); 
                                         else printf("\n"); 
                    } 
               } 
           } else printf("bad luck\n"); 
    } 
    return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值