[P3825] [NOI2017]游戏(2-SAT)

暴力枚举每个x可能的三种情况,使每个地图都只有两种可能的取值。对于每一种枚举的方案做2-SAT,如果都没有解则判断为无解。

建图时,对于一个限制条件i hi j hj:如果hi不可用,则不连边;如果hj不可用,则由i场地用hi的点向不用hi的点连边,代表i场地不能用hi;如果都可用,则由i场地用hi的点向j场地用hj的点连边,再由j场地不用hj的点向i场地不用hi的点连边。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=100010,M=200010;
struct lim{
	int x,qx,y,qy;
}l[M>>1];
struct edge{
	int y,next;
}data[M];
char str1[N],str2[5];
int n,m,d,num,num1,num2,top,len,cnt;
int acsol[N>>1][3],sol[N],h[N],dfn[N],low[N],sta[N],f[N],akind[10];
bool vis[N],insta[N],flag;
inline int read(){
	int x=0,f=0;
	char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return f?-x:x;
}
inline void add(int x,int y){
	data[++num].y=y;data[num].next=h[x];h[x]=num;
}
void tarjan(int u){
	sta[++top]=u;
	insta[u]=vis[u]=true;
	dfn[u]=low[u]=++num1;
	for(int i=h[u];i!=-1;i=data[i].next){
		int v=data[i].y;
		if(!dfn[v]){tarjan(v);low[u]=min(low[u],low[v]);}
		else if(insta[v]&&dfn[v]<low[u])low[u]=dfn[v];
	}
	if(dfn[u]==low[u]){
		++num2;
		while(dfn[sta[top]]!=low[sta[top]]){
			f[sta[top]]=num2;insta[sta[top--]]=false;
		}
		f[u]=num2;insta[sta[top--]]=false;
	}
}
bool two_sat(){
	memset(h,-1,sizeof h);num=num1=num2=top=0;
	for(int qx,qy,i=1;i<=m;i++){
		qx=l[i].qx;qy=l[i].qy;
		if(str1[l[i].x]-'a'==l[i].qx)qx=-1;
		if(str1[l[i].y]-'a'==l[i].qy)qy=-1;
		if(qx==-1)continue;
		if(qy==-1)add(acsol[l[i].x][qx],acsol[l[i].x][qx]^1);
		else{
			add(acsol[l[i].x][qx],acsol[l[i].y][qy]);
			add(acsol[l[i].y][qy]^1,acsol[l[i].x][qx]^1);
		}
	}
	memset(vis,false,sizeof vis);
	memset(dfn,0,sizeof dfn);
	for(int i=0;i<2*n;i++)if(!vis[i])tarjan(i);
	bool flag1=true;
	for(int i=0;i<n;i++)if(f[i<<1]==f[i<<1|1]){flag1=false;break;}
	return flag1;
}
void dfs(int c,int x){
	if(c>d){flag=two_sat();return;}
	str1[x]='a';sol[x<<1]=1;sol[x<<1|1]=2;acsol[x][1]=x<<1;acsol[x][2]=x<<1|1;
	dfs(c+1,akind[c+1]);if(flag)return;
	str1[x]='b';sol[x<<1]=0;sol[x<<1|1]=2;acsol[x][0]=x<<1;acsol[x][2]=x<<1|1;
	dfs(c+1,akind[c+1]);if(flag)return;
	str1[x]='c';sol[x<<1]=0;sol[x<<1|1]=1;acsol[x][0]=x<<1;acsol[x][1]=x<<1|1;
	dfs(c+1,akind[c+1]);if(flag)return;
}
int main(){
	n=read();d=read();cnt=0;
	scanf("%s",str1);len=strlen(str1);
	for(int i=0;i<len;i++){
		if(str1[i]=='x')akind[++cnt]=i;
		else{
			if(str1[i]=='a'){sol[i<<1]=1;sol[i<<1|1]=2;acsol[i][1]=i<<1;acsol[i][2]=i<<1|1;}
			else if(str1[i]=='b'){sol[i<<1]=0;sol[i<<1|1]=2;acsol[i][0]=i<<1;acsol[i][2]=i<<1|1;}
			else{sol[i<<1]=0;sol[i<<1|1]=1;acsol[i][0]=i<<1;acsol[i][1]=i<<1|1;}
		}
	}
	m=read();
	for(int i=1;i<=m;i++){
		l[i].x=read()-1;
		scanf("%s",str2);
		if(str1[l[i].x]-'a'==str2[0]-'A')l[i].qx=-1;
		else l[i].qx=str2[0]-'A';
		l[i].y=read()-1;
		scanf("%s",str2);
		if(str1[l[i].y]-'a'==str2[0]-'A')l[i].qy=-1;
		else l[i].qy=str2[0]-'A';
	}
	flag=false;dfs(1,akind[1]);
	if(!flag)printf("-1");
	else{
		for(int i=0;i<n;i++){
			if(f[i<<1]<f[i<<1|1])printf("%c",'A'+sol[i<<1]);
			else printf("%c",'A'+sol[i<<1|1]);
		}
	}
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值