NOI2017 遊戲【2-sat】

題目描述:

洛谷鏈接

題目分析:

咕咕咕。。算是2-sat裸題吧。。就枚舉一下xxaa還是bb就可以了,已經包含了所有情況,沒必要枚舉cc了。O(2d(n+m))O(2^d*(n+m))

主要是存存代碼。2-sat多組數據的時候注意scc也要清空。輸出方案直接選所在強連通分量編號小的點。

Code:

#include<bits/stdc++.h>
#define maxn 100005
#define maxm 200005
#define ID(i,j) (((i)*2)^(j))
using namespace std;
int n,m,D,p[10],X[maxn],Y[maxn];
char a[maxn],A[maxn],B[maxn];
int dfn[maxn],low[maxn],stk[maxn],top,tim,scnt,scc[maxn];
int fir[maxn],nxt[maxm],to[maxm],tot;
bool flg;
void line(int x,int y){nxt[++tot]=fir[x],fir[x]=tot,to[tot]=y;}
void add(int x,int y){line(x,y),line(y^1,x^1);}
void tarjan(int u){
	dfn[u]=low[u]=++tim,stk[++top]=u;
	for(int i=fir[u],v;i&&!flg;i=nxt[i])
		if(!dfn[v=to[i]]) tarjan(v),low[u]=min(low[u],low[v]);
		else if(!scc[v]) low[u]=min(low[u],dfn[v]);
	if(dfn[u]==low[u]){
		++scnt;
		do {scc[stk[top]]=scnt;if(scc[stk[top]^1]==scnt) {flg=1;break;}} while(stk[top--]!=u);
	}
}
bool check(){
	memset(dfn,0,(n*2+2)<<2),memset(scc,0,(n*2+2)<<2),tim=scnt=top=flg=0;
	memset(fir,0,(n*2+2)<<2),tot=0;
	for(int i=1,u,v;i<=m;i++){
		if(a[X[i]]==A[i]+32) continue;
		u=ID(X[i],A[i]=='A'?0:A[i]=='C'?1:a[X[i]]=='a'?0:1);
		if(a[Y[i]]==B[i]+32) {line(u,u^1);continue;}
		v=ID(Y[i],B[i]=='A'?0:B[i]=='C'?1:a[Y[i]]=='a'?0:1);
		add(u,v);
	}
	for(int i=2;i<=2*n+1&&!flg;i++) if(!dfn[i]) tarjan(i);
	return !flg;
}
int main()
{
	scanf("%d%d%s",&n,&D,a+1);
	for(int i=1;i<=n;i++) if(a[i]=='x') p[++*p]=i;
	scanf("%d",&m);
	for(int i=1;i<=m;i++) scanf("%d %c%d %c",&X[i],&A[i],&Y[i],&B[i]);
	for(int s=0;s<1<<D;s++){
		for(int i=0;i<D;i++) a[p[i+1]]='a'+(s>>i&1);
		if(check()){
			for(int i=1;i<=n;i++)
				if(scc[ID(i,0)]<scc[ID(i,1)]) putchar(a[i]=='a'?'B':'A');
				else putchar(a[i]=='c'?'B':'C');
			return 0;
		}
	}
	puts("-1");
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章