hdu 1814 字典序最小的2sat(暴力深搜)

题意:
     题意就是最基础的2sat,关系只有矛盾关系,然后二选一,关键是这个题目是输出字典序最小的那组解。

思路:

     输出字典序最小,用强连通那个实现不了(起码没看到有人实现),其实我们可以直接暴力,我们可以给某个点染色,分成无色(W)红色(R)和蓝色(B)红色是我们要的答案,对于每一个点我们先尽可能的吧他的a染成红色,把他的~a染成蓝色,如果发现矛盾,就是出现a是蓝色的了,那么我们就把当前这个连通块重新清成W吧其实点换成~a这样在继续染色,如果还是不行,那么就证明无解。否则这样全部染完色之后的红色点就是我们要的点。时间复杂度是 n * m * 2,大约也就n * m左右。本以为会超时,感觉到亿了,结果没有,1140ms AC ,貌似是有直接求什么字典序最小的固定算法吧!反正有也不会。哎!

#include<stdio.h>
#include<string.h>
#include<queue>

#define N_node 16000 + 100
#define N_edge 40000 + 400
#define W 0
#define R 1
#define B 2

using namespace std;


typedef struct
{
   int to ,next;
}STAR;

STAR E[N_edge];
int list[N_node] ,tot;
int col[N_node];
queue<int>q;

void add(int a ,int b)
{
   E[++tot].to = b;
   E[tot].next = list[a];
   list[a] = tot;
}

bool DFS(int s)
{
   if(col[s] == B) return 0;
   if(col[s] == R) return 1;
   col[s] = R ,col[s^1] = B;
   q.push(s);
   for(int k = list[s] ;k ;k = E[k].next)
   if(!DFS(E[k].to)) return 0;
   return 1;
}

bool solve(int n)
{
   memset(col ,W ,sizeof(col));
   for(int i = 0 ;i < n ;i ++)
   {
      if(col[i]) continue;
      while(!q.empty()) q.pop();
      if(!DFS(i))
      {
         while(!q.empty())
         {
            col[q.front()] = col[q.front()^1] = W;
            q.pop();
         }
         if(!DFS(i^1)) return 0;
      }
   }
   return 1;
}

int main ()
{
   int n ,m ,i ,a ,b;
   while(~scanf("%d %d" ,&n ,&m))
   {
      memset(list ,0 ,sizeof(list)) ,tot = 1;
      for(i = 1 ;i <= m ;i ++)
      {
         scanf("%d %d" ,&a ,&b);
         a-- ,b--;
         add(a ,b^1) ,add(b ,a^1);
      }
      if(solve(n * 2))
      {
         for(i = 1 ;i <= n * 2 ;i ++)
         if(col[i-1] == R) printf("%d
" ,i);
      }
      else printf("NIE
");
   }
   return 0;
}

原文地址:https://www.cnblogs.com/csnd/p/12063001.html