图论$cdot$2-SAT问题

2-SAT问题是这样的:有$n$个布尔变量$x_i$,另有$m$个需要满足的条件,每个条件的形式都是“$x_i$为真/假或者$x_j$为真/假”。比如:"$x_1$为真或者$x_3$为假“。注意这里的”或“是指两个条件至少有一个是正确的,比如$x_1$和$x_3$一共有$3$中组合满足"$x_1$为真或者$x_3$为假“。2-SAT问题的目标是给每个变量赋值,使得所有条件得到满足。求解2-SAT问题一般比较常见方法是构造一张有向图$G$,其中每个变量$x_i$拆成两个结点$2i$和$2i+1$,分别表示$x_i$为假和$x_i$为真。最后要为每个变量选择其中一个结点标记。比如,若标记了节点$2i$,表示$x_i$为假;如果标记了$2i+1$,表示$x_i$为真。对于“$x_i$为假或者$x_j$为假”这样的条件,我们连一条有向边$2i+1 ightarrow 2j$,表示如果标记节点$2i+1$那么也必须标记结点$j$,同理还需要连一条有向边$2j+1 ightarrow 2i$。对于其他情况,也可以类似连边。换句话说,每个条件对应两条“对称”的边。接下来逐一考虑每个没有赋值的变量,设为$x_i$。我们首先假定它为假,然后标记借点$2_i$,并且沿着有向边标记所有能标记的结点。如果标记过程中发现某个变量对应的两个结点都被标记,则“$x_i$为假”这个假定不成立,需要改成“$x_i$为真”,然后重新标记。注意,该算法无回溯过程。如果当前考虑的变量不管赋值为真还是假都会引起矛盾,可以证明整个2-SAT问题无解(即使调整以前赋值的变量也没用)。这是很显然的,每个变量只会影响到关系到该变量的表达式的取值,因此对于未赋值的变量一定与之前的赋值无关,可以分开考虑,整个问题有解需要满足每个块都有解。下面给出求解2-SAT问题的代码:

 1 struct _2_sat{
 2     int n;
 3     vector<int> G[maxn << 1];
 4     bool mark[maxn << 1];
 5     int S[maxn << 1], c;
 6     bool dfs(int x){
 7         if(mark[x ^ 1]) return 0;
 8         if(mark[x]) return 1;
 9         mark[x] = 1;
10         S[c++] = x;
11         FOR(i, 0, G[x].size() - 1) if(!dfs(G[x][i])) return 0;
12         return 1;
13     }
14     void init(int n){
15         this->n = n;
16         FOR(i, 0, 2 * n - 1) G[i].clear();
17         clr(mark, 0);
18     }
19     //x = xval or y = yval
20     void add_caluse(int x, int xval, int y, int yval){
21         x = x * 2 + xval, y = y * 2 + yval;
22         G[x ^ 1].pb(y), G[y ^ 1].pb(x);
23     }
24     bool solve(){
25         for(int i = 0; i < 2 * n; i += 2) if(!mark[i] && !mark[i + 1]){
26             c = 0;
27             if(!dfs(i)){
28                 while(c > 0) mark[S[--c]] = 0;
29                 if(!dfs(i + 1)) return 0;
30             }
31         }
32         return 1;
33     }
34 };

相关习题:

LA 3713 Astronauts

  1 #include <algorithm>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <string>
  5 #include <queue>
  6 #include <map>
  7 #include <set>
  8 #include <stack>
  9 #include <ctime>
 10 #include <cmath>
 11 #include <iostream>
 12 #include <assert.h>
 13 #pragma comment(linker, "/STACK:102400000,102400000")
 14 #define max(a, b) ((a) > (b) ? (a) : (b))
 15 #define min(a, b) ((a) < (b) ? (a) : (b))
 16 #define mp std :: make_pair
 17 #define st first
 18 #define nd second
 19 #define keyn (root->ch[1]->ch[0])
 20 #define lson (u << 1)
 21 #define rson (u << 1 | 1)
 22 #define pii std :: pair<int, int>
 23 #define pll pair<ll, ll>
 24 #define pb push_back
 25 #define type(x) __typeof(x.begin())
 26 #define foreach(i, j) for(type(j)i = j.begin(); i != j.end(); i++)
 27 #define FOR(i, s, t) for(int i = (s); i <= (t); i++)
 28 #define ROF(i, t, s) for(int i = (t); i >= (s); i--)
 29 #define dbg(x) std::cout << x << std::endl
 30 #define dbg2(x, y) std::cout << x << " " << y << std::endl
 31 #define clr(x, i) memset(x, (i), sizeof(x))
 32 #define maximize(x, y) x = max((x), (y))
 33 #define minimize(x, y) x = min((x), (y))
 34 using namespace std;
 35 typedef long long ll;
 36 const int int_inf = 0x3f3f3f3f;
 37 const ll ll_inf = 0x3f3f3f3f3f3f3f3f;
 38 const int INT_INF = (int)((1ll << 31) - 1);
 39 const double double_inf = 1e30;
 40 const double eps = 1e-14;
 41 typedef unsigned long long ul;
 42 typedef unsigned int ui;
 43 inline int readint(){
 44     int x;
 45     scanf("%d", &x);
 46     return x;
 47 }
 48 inline int readstr(char *s){
 49     scanf("%s", s);
 50     return strlen(s);
 51 }
 52 
 53 class cmpt{
 54 public:
 55     bool operator () (const int &x, const int &y) const{
 56         return x > y;
 57     }
 58 };
 59 
 60 int Rand(int x, int o){
 61     //if o set, return [1, x], else return [0, x - 1]
 62     if(!x) return 0;
 63     int tem = (int)((double)rand() / RAND_MAX * x) % x;
 64     return o ? tem + 1 : tem;
 65 }
 66 ll ll_rand(ll x, int o){
 67     if(!x) return 0;
 68     ll tem = (ll)((double)rand() / RAND_MAX * x) % x;
 69     return o ? tem + 1 : tem;
 70 }
 71 
 72 void data_gen(){
 73     srand(time(0));
 74     freopen("in.txt", "w", stdout);
 75     int kases = 10;
 76     printf("%d
", kases);
 77     while(kases--){
 78         ll sz = 100000;
 79         printf("%d
", sz);
 80         FOR(i, 1, sz){
 81             int o = Rand(2, 0);
 82             int x = Rand(1e9, 1);
 83             int y1 = Rand(1e9, 1), y2 = Rand(1e9, 1);
 84             if(o == 0) printf("%d %d %d %d
", x, y1, x, y1);
 85             else printf("%d %d %d %d
", y1, x, y2, x);
 86         }
 87     }
 88 }
 89 const int maxn = 1e5 + 10;
 90 int n, m;
 91 ll sum;
 92 int id[maxn];
 93 int age[maxn];
 94 int head[maxn << 1];
 95 struct E{
 96     int to, nex;
 97 }e[maxn << 2];
 98 bool vis[maxn << 1];
 99 int N;
100 void addE(int x, int y){
101     e[N].nex = head[x];
102     e[N].to = y;
103     head[x] = N++;
104 }
105 int stk[maxn], k;
106 bool dfs(int u){
107     if(vis[u]) return 1;
108     vis[u] = 1;
109     stk[k++] = u;
110     if(vis[u] && vis[u ^ 1]) return 0;
111     for(int i = head[u]; ~i; i = e[i].nex){
112         int v = e[i].to;
113         if(!dfs(v)) return 0;
114     }
115     return 1;
116 }
117 
118 bool solve(int u){
119     k = 0;
120     if(dfs(2 * u)) return 1;
121     while(k) vis[stk[--k]] = 0;
122     if(dfs(2 * u + 1)) return 1;
123     return 0;
124 }
125 
126 int main(){
127     //data_gen(); return 0;
128     //C(); return 0;
129     int debug = 0;
130     if(debug) freopen("in.txt", "r", stdin);
131     //freopen("out.txt", "w", stdout);
132     while(~scanf("%d%d", &n, &m) && n){
133         sum = 0;
134         FOR(i, 0, n - 1) age[i] = readint(), sum += age[i];
135         FOR(i, 0, n - 1) id[i] = (ll)age[i] * n >= sum ? 0 : 1;
136         clr(head, -1), N = 0;
137         FOR(i, 0, m - 1){
138             int x = readint() - 1, y = readint() - 1;
139             //cc[i][0] = x, cc[i][1] = y;
140             addE(2 * x, 2 * y + 1);
141             if(id[x] == id[y]) addE(2 * x + 1, 2 * y);
142             addE(2 * y, 2 * x + 1);
143             if(id[x] == id[y]) addE(2 * y + 1, 2 * x);
144         }
145         int ok = 1;
146         clr(vis, 0);
147         FOR(i, 0, n - 1) if(!vis[2 * i] && !vis[2 * i + 1] && !solve(i)){
148             ok = 0;
149             break;
150         }
151         if(!ok) puts("No solution.");
152         else FOR(i, 0, n - 1) putchar(!vis[2 * i + 1] ? 'C' : 'A' + id[i]), putchar('
');
153         //int res = verdict();
154         //printf("verdict :: %s", res ? "ok
" : "err
");
155     }
156     return 0;
157 }
code:
原文地址:https://www.cnblogs.com/astoninfer/p/5766961.html