Description:
小 L 计划进行(n)场游戏,每场游戏使用一张地图,小 L 会选择一辆车在该地图上完成游戏。小 L 的赛车有三辆,分别用大写字母ABC表示。地图一共有四种,分别用小写字母x、a、b、c表示。其中,赛车A不适合在地图a上使用,赛车B不适合在地图b上使用,赛车C不适合在地图c上使用,而地图x则适合所有赛车参加。适合所有赛车参加的地图并不多见,最多只会有d张。(n)场游戏的地图可以用一个小写字母组成的字符串描述。例如:S=xaabxcbc表示小 L 计划进行(8)场游戏,其中第(1)场和第(5)场的地图类型是x,适合所有赛车,第(2)场和第(3)场的地图是a,不适合赛车A,第(4)场和第(7)场的地图是b,不适合赛车B,第(6)场和第(8)场的地图是c,不适合赛车C。小 L 对游戏有一些特殊的要求,这些要求可以用四元组 ((i, h_i, j, h_j))来描述,表示若在第(i)场使用型号为(h_i)的车子,则第(j)场游戏要使用型号为(h_j)的车子。你能帮小 L 选择每场游戏使用的赛车吗?如果有多种方案,输出任意一种方案。如果无解,输出 “-1’’(不含双引号)。
Hint :
(nle 10^5)
Solution :
考虑如果没有(x)地图,这就是个普通的(2-SAT)
但连边还是有细节的:
若 (i) 不适合 (h_i) 则直接忽视
若 (i) 适合 (h_i) 但 (j) 不适合 (h_j) ,则连边 (i->i^{'}) ,表示一定不能选 (h_i)
其他的就是一般情况了
现在加入(x)地图后变成了(3-SAT),为不可做的(NP)问题
观察到 (x地图数量 le 8)
考虑枚举那个地图是 (a) 还是 (b)
是 (a) 则能走 (b) 和 (c)
是 (b) 则能走 (a) 和 (c)
这样便覆盖了所有情况
复杂度 (O(2^8*(n+m))) 足已通过本题
而这题还要求输出方案,那我们就按字典序连边和输出,注意要分类讨论
#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define ls p<<1
#define rs p<<1|1
using namespace std;
typedef long long ll;
const int mxn=1e5+5;
int n,m,d,k,cnt,tot,col;
int x[mxn],y[mxn],hd[mxn],bl[mxn],pos[mxn],dfn[mxn],low[mxn],ins[mxn];
char p[mxn],q[mxn],s[mxn],ans[mxn];
stack<int > st;
struct ed {
int to,nxt;
}t[mxn<<1];
inline void add(int u,int v) {
t[++cnt]=(ed) {v,hd[u]}; hd[u]=cnt;
}
inline int read() {
char c=getchar(); int x=0,f=1;
while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();}
while(c<='9'&&c>='0') {x=(x<<3)+(x<<1)+(c&15);c=getchar();}
return x*f;
}
inline void chkmax(int &x,int y) {if(x<y) x=y;}
inline void chkmin(int &x,int y) {if(x>y) x=y;}
void clr() {
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(ins,0,sizeof(ins));
memset(bl,0,sizeof(bl));
memset(hd,0,sizeof(hd));
col=cnt=tot=0;
}
void tj(int u)
{
dfn[u]=low[u]=++tot; ins[u]=1; st.push(u);
for(int i=hd[u];i;i=t[i].nxt) {
int v=t[i].to;
if(!dfn[v]) tj(v),chkmin(low[u],low[v]);
else if(ins[v]) chkmin(low[u],dfn[v]);
}
if(low[u]==dfn[u]) {
++col;
do {
bl[u]=col; u=st.top();
st.pop(); ins[u]=0;
} while(low[u]!=dfn[u]);
}
}
int check() {
for(int i=1;i<=2*n;++i)
if(!dfn[i]) tj(i);
for(int i=1;i<=n;++i) {
if(bl[i]==bl[i+n]) return 0;
if(bl[i]<bl[i+n]) ans[i]=(s[i]=='A'?'B':'A');
else ans[i]=(s[i]=='C'?'B':'C');
}
for(int i=1;i<=n;++i) printf("%c",ans[i]);
return 1;
}
void solve()
{
for(int i=0;i<(1<<d);++i) { //枚举x地图
clr();
for(int j=1;j<=d;++j) s[pos[j]]=((i>>(j-1))&1)?'A':'B';
for(int j=1;j<=m;++j) {
if(p[j]==s[x[j]]) continue ;
if(q[j]==s[y[j]]) {
if(p[j]=='C'||(p[j]=='B'&&s[x[j]]=='C')) add(x[j]+n,x[j]);
else add(x[j],x[j]+n);
continue ;
} //特殊情况
int tag1=0,tag2=0;
if(p[j]=='C'||(p[j]=='B'&&s[x[j]]=='C')) tag1=n;
if(q[j]=='C'||(q[j]=='B'&&s[y[j]]=='C')) tag2=n;
add(x[j]+tag1,y[j]+tag2); add(y[j]-tag2+n,x[j]-tag1+n);
//巧妙的分类讨论,避免了冗长的代码
}
if(check()) return ;
}
printf("-1");
}
int main()
{
n=read(); d=read();
scanf("%s",s+1); m=read();
for(int i=1;i<=n;++i) {
if(s[i]=='x') pos[++k]=i;
s[i]-=32;
}
for(int i=1;i<=m;++i) scanf("%d %c %d %c",&x[i],&p[i],&y[i],&q[i]);
solve();
return 0;
}