题面
https://www.luogu.org/problem/P3825
题解
我发现这些年我学的$2-sat$竟然一直是假的,醉了醉了。
我们看一下$2-sat$的形式:
如果$p$,那么$q$。
数学上学过,一个命题成立,那么它的逆否命题成立。在这里,他的逆否命题也是可以完全确定的。
所以,如果非$q$,那么非$p$。
形象理解一下,如果非$q$,那么$p$变量的值肯定不是随便取的,如果它成立,而$q$又不成立,那就假了。所以也要非$p$
所以在连边的时候,也要连它的“逆否边”。
我认为,$2-sat$是可解的,和“它的逆否命题唯一确定”的性质是很有关系的,如果只连原命题的边,解集会形成一个闭合子图的形式。。。。。。。。
#include<stack>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#define ri register int
#define N 100500
using namespace std;
int n,d,m,d1[N],t1[N],d2[N],t2[N],sani,c[N],sat[N];
int dfn[N],low[N],cnt,clo,bel[N];
bool ins[N],vis[N];
char s[N];
stack<int> sta;
vector<int> to[N];
void tarjan(int x) {
dfn[x]=low[x]=++clo;
sta.push(x); ins[x]=1;
for (ri i=0;i<to[x].size();++i) {
int y=to[x][i];
if (dfn[y]) {
if (ins[y]) low[x]=min(low[x],dfn[y]);
}
else {
tarjan(y);
low[x]=min(low[x],low[y]);
}
}
if (low[x]==dfn[x]) {
++cnt;
while (1) {
int t=sta.top(); sta.pop();
bel[t]=cnt; ins[t]=0;
if (t==x) break;
}
}
}
int fan(int x) {
if (x>n) return x-n; else return x+n;
}
int id(int cur,int opt) {
if ((s[cur]=='x'&&(1<<c[cur])&sani)||s[cur]=='a') {
if (opt==2) return cur;
if (opt==3) return cur+n;
if (opt==1) return -1;
}
if ((s[cur]=='x'&&!((1<<c[cur])&sani))||s[cur]=='b') {
if (opt==1) return cur;
if (opt==3) return cur+n;
if (opt==2) return -1;
}
if (s[cur]=='c') {
if (opt==1) return cur;
if (opt==2) return cur+n;
if (opt==3) return -1;
}
return -1;
}
bool dfs() {
cnt=0; clo=0;
for (ri i=1;i<=2*n;i++) to[i].clear();
for (ri i=1;i<=2*n;i++) dfn[i]=low[i]=0;
memset(ins,0,sizeof(ins));
for (ri i=1;i<=m;i++) {
int u=id(d1[i],t1[i]),v=id(d2[i],t2[i]);
if (u==-1) continue;
if (v==-1) v=fan(u);
to[u].push_back(v);
if (v!=fan(u)) to[fan(v)].push_back(fan(u));
}
for (ri i=1;i<=2*n;i++) if (!dfn[i]) tarjan(i);
for (ri i=1;i<=n;i++) if (bel[i]==bel[i+n]) return 0;
return 1;
}
void bfs(int x) {
if (vis[x]) return;
vis[x]=1;
if (x>n) {
int cur=x-n;
if ((s[cur]=='x'&&(1<<c[cur])&sani) || s[cur]=='a') sat[cur]=2;
else if ((s[cur]=='x'&&!((1<<c[cur])&sani)) || s[cur]=='b') sat[cur]=2;
else if (s[cur]=='c') sat[cur]=1;
}
else {
int cur=x;
if ((s[cur]=='x'&&(1<<c[cur])&sani) || s[cur]=='a') sat[cur]=1;
else if ((s[cur]=='x'&&!((1<<c[cur])&sani)) || s[cur]=='b') sat[cur]=0;
else if (s[cur]=='c') sat[cur]=0;
}
}
void print() {
for (ri i=1;i<=n;i++) if (bel[i]<bel[i+n]) bfs(i); else bfs(i+n);
for (ri i=1;i<=n;i++) putchar('A'+sat[i]);
}
int main(){
char no[5],np[5];
scanf("%d %d",&n,&d);
scanf("%s",s+1);
int cc=-1;
for (ri i=1;i<=n;++i) if (s[i]=='x') c[i]=++cc;
scanf("%d",&m);
for (ri i=1;i<=m;++i) {
scanf("%d %s %d %s",&d1[i],no,&d2[i],np);
if (no[0]=='A') t1[i]=1;
else if (no[0]=='B') t1[i]=2;
else if (no[0]=='C') t1[i]=3;
if (np[0]=='A') t2[i]=1;
else if (np[0]=='B') t2[i]=2;
else if (np[0]=='C') t2[i]=3;
}
for (sani=0;sani<(1<<d);++sani) if (dfs()) {
print();
return 0;
}
printf("-1");
return 0;
}