[BZOJ4945][NOI2017]游戏(2-SAT)
裸题。对于x地图,强行枚举让它有一个无法行驶,显然只需要枚举'A'和'B'即可。
没有什么难度,但是如果在考场上区别就会很大,因为2-SAT不是平时常考内容,容易因为逆否命题连边等模板不熟的问题,既耽误时间又拿不到分。
有几个注意点:
1.判断一下命题中是否有已经确定不能走的地图,特殊处理。(强制让某个命题i不选(或者强制让命题i'选)的方法是:连边i->i')。
2.关于输出方案,有一种显然的方法是按缩点后的反向拓扑序遍历,能选则选(让限制尽量宽松)。但是注意到求SCC时得到的强连通块标号实际上已经是反向拓扑序了,所以我们可以直接贪心:对于命题i,如果bel[i]<bel[i'],则选i,否则选i’。
(上面两个的正确性都只能感性理解。。)
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #define mem(a) memset(a,0,sizeof(a)) 5 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 6 using namespace std; 7 8 const int N=100010; 9 int n,w,m,len,tim,tot,scc,cnt,top,p[N],h[N],to[N<<1],nxt[N<<1]; 10 int ans[N],a[N],stk[N],inq[N],low[N],dfn[N],bel[N]; 11 struct Q{ int u,wu,v,wv; }q[N]; 12 char S[N],ch1,ch2; 13 void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; } 14 15 int F(int x,int k){ 16 if (k==1) return x<<1; 17 if (k==2) { if (a[x]==1) return x<<1; else return (x<<1)|1; } 18 return (x<<1)|1; 19 } 20 21 char get(int x,int k){ 22 if (k==1) { if (a[x]==1) return 'B'; else return 'A'; } 23 if (k==2) { if (a[x]==1 || a[x]==2) return 'C'; else return 'B'; } 24 return 0; 25 } 26 27 void tarjan(int x){ 28 dfn[x]=low[x]=++tim; inq[x]=1; stk[++top]=x; 29 for (int i=h[x],k; i; i=nxt[i]) 30 if (!dfn[k=to[i]]) tarjan(k),low[x]=min(low[x],low[k]); 31 else if (inq[k]) low[x]=min(low[x],dfn[k]); 32 if (low[x]==dfn[x]){ 33 scc++; int t; 34 do { t=stk[top--]; bel[t]=scc; inq[t]=0; }while (t!=x); 35 } 36 } 37 38 void jud(){ 39 mem(h); mem(dfn); mem(inq); scc=cnt=top=tim=0; 40 rep(i,1,m){ 41 int x=F(q[i].u,q[i].wu),y=F(q[i].v,q[i].wv); 42 if (a[q[i].u]==q[i].wu) continue; 43 if (a[q[i].v]==q[i].wv) add(x,x^1); else add(x,y),add(y^1,x^1); 44 } 45 rep(i,2,(n<<1)|1) if (!dfn[i]) tarjan(i); 46 int f=0; rep(i,1,n) if (bel[i<<1]==bel[(i<<1)|1]) { f=1; break; } 47 if (!f){ 48 rep(i,1,n) printf("%c",(bel[i<<1]<bel[(i<<1)|1])?get(i,1):get(i,2)); 49 exit(0); 50 } 51 } 52 53 void dfs(int x){ 54 if (x>w){ jud(); return; } 55 a[p[x]]=1; dfs(x+1); a[p[x]]=2; dfs(x+1); 56 } 57 58 int main(){ 59 freopen("bzoj4945.in","r",stdin); 60 freopen("bzoj4945.out","w",stdout); 61 scanf("%d%d",&n,&w); scanf("%s",S+1); len=strlen(S+1); 62 rep(i,1,len){ 63 if (S[i]=='a') a[i]=1; 64 if (S[i]=='b') a[i]=2; 65 if (S[i]=='c') a[i]=3; 66 if (S[i]=='x') a[i]=0,p[++tot]=i; 67 } 68 scanf("%d",&m); 69 rep(i,1,m){ 70 scanf("%d %c%d %c",&q[i].u,&ch1,&q[i].v,&ch2); 71 q[i].wu=ch1-'A'+1; q[i].wv=ch2-'A'+1; 72 } 73 dfs(1); puts("-1"); 74 return 0; 75 }