[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 }
原文地址:https://www.cnblogs.com/HocRiser/p/8981446.html