【NOI2017】游戏 题解(2-SAT+缩点)
题目大意:有四种场地$a,b,c,x$和三种赛车$A,B,C$,$a$不能跑$A$,$b$不能跑$B$,$c$不能跑$C$,$x$都可以跑。给定$n$个场地和$m$个四元组$(i,h_i,j,h_j)$,意为如果在第$i$个场地跑$h_i$,那么第$j$个场地必须跑$h_j$。输出一种合法方案。若无输出$-1$。
----------------------------------
此题难在建图。把建图搞定就是一个裸的2-SAT板子。
我们规定$0$为每种场地的第一种能跑的车(按字典序),$1$表示第二种能跑的车。对于约束条件,我们有$3$种情况:
1.$h_i$类型的车与$i$冲突,那么我们直接跳过,不用管它。
2.$h_j$类型的车与$j$冲突,那么我们让$i$向$i'$连边,表示如果选择$h_i$则无解。
3.没有冲突情况。那么我们直接按照2-SAT建图方式建就好,即$i$向$j$连边,$j'$向$i'$连边。
对于$x$,我们只要把它当作某一种特定的场地,然后$dfs$枚举所有情况就好。把它当作任意两种场地就可以包含所有可能情况。
时间复杂度$O(2^dn)$。
PS:一开始我超级傻逼,写了一串$if$来判各种情况还各种出锅;后面突然想到只要写个函数判断就行了草。从早上7点来学校写,一直到上午10点才过……
代码:
#include<bits/stdc++.h> using namespace std; const int maxn=200005; int dfn[maxn],low[maxn],vis[maxn],pos[maxn],jishu,tot; stack<int> st; int head[maxn],cnt,n,m,d; int query[maxn][3]; char ch[maxn][3],c[maxn],s[maxn]; struct node { int next,to; }edge[maxn]; inline int read() { int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();} while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();} return x*f; } inline void add(int from,int to) { edge[++cnt].next=head[from]; edge[cnt].to=to; head[from]=cnt; } inline void clear() { jishu=tot=cnt=0; memset(head,0,sizeof(head)); memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(pos,0,sizeof(pos)); while(!st.empty()) st.pop(); } inline void tarjan(int now) { dfn[now]=low[now]=++jishu; st.push(now);vis[now]=1; for (int i=head[now];i;i=edge[i].next) { int to=edge[i].to; if (!dfn[to]) tarjan(to),low[now]=min(low[now],low[to]); else if (vis[to]) low[now]=min(low[now],dfn[to]); } if (low[now]==dfn[now]) { tot++; while(st.top()!=now) { int x=st.top();st.pop(); vis[x]=0; pos[x]=tot; } int x=st.top();st.pop(); vis[x]=0; pos[x]=tot; } } inline bool check(int pos,char x) { if (x+32==s[pos]) return 1; return 0; } inline bool get(int pos,char x) { if (s[pos]=='a') return x=='B'?0:1; else return x=='A'?0:1; } inline void dfs(int now) { if (now>n) { clear(); for (int i=1;i<=m;i++) { int a=query[i][1],b=query[i][2]; if (check(a,ch[i][1])) continue; if (check(b,ch[i][2])) { int flag=get(a,ch[i][1]); if (!flag) add(a,a+n); else add(a+n,a); continue; } else { int x=get(a,ch[i][1]),y=get(b,ch[i][2]); if (x==0&&y==0) add(a,b),add(b+n,a+n); if (x==0&&y==1) add(a,b+n),add(b,a+n); if (x==1&&y==0) add(a+n,b),add(b+n,a); if (x==1&&y==1) add(a+n,b+n),add(b,a); } } for (int i=1;i<=2*n;i++) if(!dfn[i]) tarjan(i); for (int i=1;i<=n;i++) if (pos[i]==pos[i+n]) return; for (int i=1;i<=n;i++) { if (pos[i]<pos[i+n]) { if (s[i]=='a') printf("B"); else printf("A"); } else { if (s[i]=='c') printf("B"); else printf("C"); } } exit(0); } if (c[now]=='a') s[now]='a',dfs(now+1); if (c[now]=='b') s[now]='b',dfs(now+1); if (c[now]=='c') s[now]='c',dfs(now+1); if (c[now]=='x'){s[now]='a',dfs(now+1);s[now]='b',dfs(now+1);} } int main() { n=read(),d=read(); cin>>(c+1); m=read(); for (int i=1;i<=m;i++) { query[i][1]=read(),cin>>ch[i][1]; query[i][2]=read(),cin>>ch[i][2]; } dfs(1); printf("-1"); return 0; }