题面
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; }