#【NOI2017】遊戲(搜索,2-sat) ##題面 BZOJ的SPJ是假的 茲磁洛谷ios
##題解 若是沒有$x$地圖的影響 這就是一個裸的$2-sat$問題優化
可是如今有不超過$8$個$x$地圖的影響 咱們不難想到枚舉$x$地圖的狀態再來$2-sat$判斷剩餘是否可行。 這樣的複雜度是$O(3^dn)$,稍微算一下發現這個複雜度有點假ui
考慮如何優化,咱們枚舉$x$地圖不連什麼 表面上看起來仍是$O(3^dn)$ 可是,當他等價於$a,b$兩種地圖時,$2^d$種方案中必定會包含着最後的解,也就是說,$a,b$兩種地圖替換$x$的全部狀態,等價於$a,b,c$三種地圖替換$x$ 這樣的複雜度是$O(2^dn)$spa
如今考慮$2-sat$如何連邊 對於限制$i->j$ 顯然直接鏈接$i->j$ 而且,若是$j'$被選擇,那麼必須選擇$i'$ 因此,同時鏈接$j'->i'$ 一些沒有意義的連邊能夠直接省略。code
至於輸出方案,$Tarjan$求出來的強連通份量已經和拓撲序相關,所以沒有必要從新建圖拓撲排序排序
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> #include<set> #include<map> #include<vector> #include<queue> using namespace std; #define ll long long #define RG register #define MAX 333333 inline int read() { RG int x=0,t=1;RG char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')t=-1,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return x*t; } char g[MAX]; struct Limit{int i,j;char a,b;}q[MAX]; int n,D,m,pos[20]; struct Line{int v,next;}e[MAX<<3]; int h[MAX],cnt; int p[MAX]; inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;} bool fl; void Build() { memset(h,0,sizeof(h));cnt=1;fl=true; for(int i=1;i<=n;++i) { p[i]=p[i+n]=p[i+n+n]=0; if(g[i]=='a')p[i+n]=i+n+n,p[i+n+n]=i+n; else if(g[i]=='b')p[i]=i+n+n,p[i+n+n]=i; else p[i]=i+n,p[i+n]=i; } for(int i=1;i<=m;++i) { int u=q[i].i,v=q[i].j; int a=q[i].a-65,b=q[i].b-65; if(u==v&&a==b)continue; if(g[u]-97==a)continue; if(g[v]-97==b){Add(u+a*n,p[u+a*n]);continue;} Add(u+a*n,v+b*n); Add(p[v+b*n],p[u+a*n]); } } int dfn[MAX],low[MAX],S[MAX],top; int gr,G[MAX],tim,ans[MAX]; bool Ins[MAX]; void Tarjan(int u) { dfn[u]=low[u]=++tim; S[++top]=u;Ins[u]=true; int v; for(int i=h[u];i;i=e[i].next) { v=e[i].v; if(!dfn[v])Tarjan(v),low[u]=min(low[u],low[v]); else if(Ins[v])low[u]=min(low[u],dfn[v]); } if(dfn[u]==low[u]) { ++gr; do{v=S[top--];G[v]=gr;Ins[v]=false;}while(u!=v); } } void Calc() { Build();gr=tim=0;if(!fl)return; memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(G,0,sizeof(G)); for(int i=1;i<=n+n+n;++i)if(!dfn[i])Tarjan(i); for(int i=1;i<=n+n+n;++i)if(G[i]==G[p[i]])return; for(int i=1;i<=n;++i) { if(g[i]=='a')(G[i+n]<G[i+n+n])?ans[i]=1:ans[i]=2; if(g[i]=='b')(G[i]<G[i+n+n])?ans[i]=0:ans[i]=2; if(g[i]=='c')(G[i]<G[i+n])?ans[i]=0:ans[i]=1; } for(int i=1;i<=n;++i)putchar(ans[i]+65);puts(""); exit(0); } void dfs(int x) { if(x==D+1){Calc();return;} g[pos[x]]='a';dfs(x+1); g[pos[x]]='b';dfs(x+1); } int main() { n=read();D=read();D=0; scanf("%s",g+1); m=read(); for(int i=1;i<=m;++i) q[i].i=read(),q[i].a=getchar(),q[i].j=read(),q[i].b=getchar(); for(int i=1;i<=n;++i) if(g[i]=='x')pos[++D]=i; dfs(1); puts("-1"); return 0; }