[NOI2017]游戏【2-SAT(Tarjan+拓扑)+状态压缩二进制枚举】

题目链接

  有N个场地,每个场地有不适应的赛车,这些场地不能派对应的赛车参赛,又有适合所有赛车的图(不超过8个),并且有的车有怪癖,i图使用col[i]车,则要求j图使用col[j]车。问,是否存在一种方案满足以上条件?并且输出,否则为-1。

  很明显的,对于适合所有赛车的图,我们可以使用二进制枚举它是哪种图——假设它不适合'A'车、'B'车。

  那么,对于剩下的图,我们可以直接进行构造,如果在第i个场地开col[i]车(u),需要让第j个场地开col[j]车(v),我们就让" u -> v ",同理,根据2—SAT的原则,其逆否命题显然成立" v' -> u' "。

  然后,我们先Tarjan缩点来看合法性,再如果合法的话,可以从底向上拓扑来选出一种方案。

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cmath>
  4 #include <string>
  5 #include <cstring>
  6 #include <algorithm>
  7 #include <limits>
  8 #include <vector>
  9 #include <stack>
 10 #include <queue>
 11 #include <set>
 12 #include <map>
 13 #include <bitset>
 14 #include <unordered_map>
 15 #include <unordered_set>
 16 #define lowbit(x) ( x&(-x) )
 17 #define pi 3.141592653589793
 18 #define e 2.718281828459045
 19 #define INF 0x3f3f3f3f
 20 #define HalF (l + r)>>1
 21 #define lsn rt<<1
 22 #define rsn rt<<1|1
 23 #define Lson lsn, l, mid
 24 #define Rson rsn, mid+1, r
 25 #define QL Lson, ql, qr
 26 #define QR Rson, ql, qr
 27 #define myself rt, l, r
 28 #define pii pair<int, int>
 29 #define MP(a, b) make_pair(a, b)
 30 using namespace std;
 31 typedef unsigned long long ull;
 32 typedef unsigned int uit;
 33 typedef long long ll;
 34 const int maxN = 1e5 + 10, maxM = 2e5 + 10;
 35 int N, M, D, dth[10], head[maxN << 1], cnt, id[maxN][3] = {0}, col[maxN][3], all;
 36 struct Eddge
 37 {
 38     int nex, to;
 39     Eddge(int a=-1, int b=0):nex(a), to(b) {}
 40 } edge[maxM << 1];
 41 inline void addEddge(int u, int v)
 42 {
 43     edge[cnt] = Eddge(head[u], v);
 44     head[u] = cnt++;
 45 }
 46 char s[maxN];
 47 inline void init()
 48 {
 49     cnt = 0;
 50     for(int i = 0; i <= all; i ++) head[i] = -1;
 51 }
 52 struct save_edge
 53 {
 54     int u, v;
 55     char s0, s1;
 56     save_edge(int a=0, char _a=0, int b=0, char _b=0):u(a), s0(_a), v(b), s1(_b) {}
 57 } se[maxM];
 58 void build_Graph()
 59 {
 60     init();
 61     char s0, s1;
 62     for(int i = 1, u, v; i <= M; i ++)
 63     {
 64         u = se[i].u; v = se[i].v;
 65         s0 = se[i].s0; s1 = se[i].s1;
 66         if(s0 + 32 == s[u]) continue;
 67         if(s1 + 32 == s[v])
 68         {
 69             if(col[u][0] == s0) addEddge(id[u][0], id[u][1]);
 70             else addEddge(id[u][1], id[u][0]);
 71         }
 72         else
 73         {
 74             int iu = 0, iv = 0;
 75             if(col[u][iu] != s0) iu ++;
 76             if(col[v][iv] != s1) iv ++;
 77             addEddge(id[u][iu], id[v][iv]);
 78             addEddge(id[v][iv ^ 1], id[u][iu ^ 1]);
 79         }
 80     }
 81 }
 82 int dfn[maxN << 1], low[maxN << 1], tot, Stap[maxN << 1], Stop, Belong[maxN << 1], Bcnt;
 83 bool instack[maxN << 1];
 84 void Tarjan(int u)
 85 {
 86     dfn[u] = low[u] = ++tot;
 87     Stap[++Stop] = u;
 88     instack[u] = true;
 89     for(int i = head[u], v; ~i; i = edge[i].nex)
 90     {
 91         v = edge[i].to;
 92         if(!dfn[v])
 93         {
 94             Tarjan(v);
 95             low[u] = min(low[u], low[v]);
 96         }
 97         else if(instack[v]) low[u] = min(low[u], dfn[v]);
 98     }
 99     if(low[u] == dfn[u])
100     {
101         int v; Bcnt++;
102         do
103         {
104             v = Stap[Stop --];
105             instack[v] = false;
106             Belong[v] = Bcnt;
107         } while(u ^ v);
108     }
109 }
110 queue<int> Q;
111 int du[maxN << 1], tp_id[maxN << 1], tp_tot;
112 vector<int> to[maxN << 1];
113 void tp_sort()
114 {
115     while(!Q.empty()) Q.pop();
116     for(int i = 1; i <= Bcnt; i ++) if(!du[i]) Q.push(i);
117     tp_tot = 0;
118     while(!Q.empty())
119     {
120         int u = Q.front(); Q.pop();
121         tp_id[u] = ++tp_tot;
122         for(int v : to[u])
123         {
124             du[v] --;
125             if(!du[v]) Q.push(v);
126         }
127     }
128 }
129 bool Solve()
130 {
131     tot = Stop = Bcnt = 0;
132     for(int i = 1; i <= all; i ++) { dfn[i] = low[i] = 0; instack[i] = false; }
133     for(int i = 1; i <= all; i ++) if(!dfn[i]) Tarjan(i);
134     for(int i = 1; i <= N; i ++)
135     {
136         if(Belong[id[i][0]] == Belong[id[i][1]]) return false;
137     }
138     for(int i = 1; i <= Bcnt; i ++) { to[i].clear(); du[i] = 0; }
139     for(int u = 1; u <= all; u ++)
140     {
141         for(int i = head[u], v; ~i; i = edge[i].nex)
142         {
143             v = edge[i].to;
144             if(Belong[u] == Belong[v]) continue;
145             to[Belong[v]].push_back(Belong[u]);
146             du[Belong[u]] ++;
147         }
148     }
149     tp_sort();
150     for(int i = 1; i <= N; i ++)
151     {
152         if(tp_id[Belong[id[i][0]]] < tp_id[Belong[id[i][1]]]) printf("%c", col[i][0]);
153         else printf("%c", col[i][1]);
154     }
155     printf("
");
156     return true;
157 }
158 int main()
159 {
160     scanf("%d%d", &N, &D);
161     scanf("%s", s + 1);
162     all = 0; int kd = 0;
163     for(int i = 1; i <= N; i ++)
164     {
165         id[i][0] = ++all;
166         id[i][1] = ++all;
167         switch (s[i])
168         {
169             case 'a': { col[i][0] = 'B'; col[i][1] = 'C'; break; }
170             case 'b': { col[i][0] = 'A'; col[i][1] = 'C'; break; }
171             case 'c': { col[i][0] = 'A'; col[i][1] = 'B'; break; }
172             default: { dth[kd ++] = i; break; }
173         }
174     }
175     scanf("%d", &M);
176     char s0[3], s1[3];
177     for(int i = 1, u, v; i <= M; i ++)
178     {
179         scanf("%d%s%d%s", &u, s0, &v, s1);
180         se[i] = save_edge(u, s0[0], v, s1[0]);
181     }
182     bool ok = false;
183     for(int Sta = 0; !ok && Sta < (1 << D); Sta ++)
184     {
185         for(int i = 0; i < D; i ++)
186         {
187             if((Sta >> i) & 1)
188             {
189                 s[dth[i]] = 'b';
190                 col[dth[i]][0] = 'A';
191                 col[dth[i]][1] = 'C';
192             }
193             else
194             {
195                 s[dth[i]] = 'a';
196                 col[dth[i]][0] = 'B';
197                 col[dth[i]][1] = 'C';
198             }
199         }
200         build_Graph();
201         ok = Solve();
202     }
203     if(!ok) printf("-1
");
204     return 0;
205 }
206 /*
207 4 0
208 abac
209 3
210 1 B 2 A
211 2 C 3 B
212 3 B 4 C
213 */
原文地址:https://www.cnblogs.com/WuliWuliiii/p/14063414.html