[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("\n"); 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\n"); 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 */
标签:10,Tarjan,dth,long,define,NOI2017,include,col,SAT 来源: https://www.cnblogs.com/WuliWuliiii/p/14063414.html