【NOI2017游戏】 枚举+2SAT

%%%2SAT大神love 小 L 计划进行  场游戏,每场游戏使用一张地图,小 L 会选择一辆车在该地图上完成游戏。 小 L 的赛车有三辆,分别用大写字母 BC 表示。地图一共有四种,分别用小写字母abc 表示。 其中,赛车  不适合在地图 a 上使用,赛车 B 不适合在地图 b 上使用,赛车 C 不适合在地图 c 上使用,而地图  则适合所有赛车参加。 适合所有赛车参加的地图并不多见,最多只会有  张。  场游戏的地图可以用一个小写字母组成的字符串描述。例如:S 表示小L计划进行 8 场游戏,其中第  场和第  场的地图类型是 ,适合所有赛车,第 2场和第 场的地图是 ,不适合赛车 ,第  场和第  场的地图是 ,不适合赛车 ,第  场和第  场的地图是 ,不适合赛车 。 小 L 对游戏有一些特殊的要求,这些要求可以用四元组 (i, h_i, j, h_j) 来描述,表示若在第 i 场使用型号为 h_i 的车子,则第  场游戏要使用型号为 h_j 的车子。 你能帮小 L 选择每场游戏使用的赛车吗?如果有多种方案,输出任意一种方案。 如果无解,输出 -1

输入格式

输入第一行包含两个非负整数 ,。 输入第二行为一个字符串 SndS 的含义见题目描述,其中  包含  个字符,且其中恰好 d 个为小写字母 x。 输入第三行为一个正整数  ,表示有 m 条用车规则。 接下来  行,每行包含一个四元组 i,h_i,j,h_j ,其中 i,j 为整数,h_i,h_j 为字符 A 、B 或 C,含义见题目描述。

输出格式

输出一行。 若无解输出 -1

样例

样例输入

3 1
xcc
1
1 A 2 B

样例输出

ABA
小 L 计划进行 3 场游戏,其中第  场的地图类型是 x,适合所有赛车,第  场和第 3 场的地图是,不适合赛车 。 小 L 希望:若第  场游戏使用赛车 A,则第 2 场游戏使用赛车 。 那么为这  场游戏分别安排赛车 AA 可以满足所有条件。 若依次为  场游戏安排赛车为 BBB 或 BAA时,也可以满足所有条件,也被视为正确答案。 但依次安排赛车为 AAB 或 ABC 时,因为不能满足所有条件,所以不被视为正确答案。

数据范围与提示

Screen Shot 2018-03-12 at 23.17.17.png 除了万能图就是一个裸的2-sat依赖.考虑万能图也就是直接2^d枚举图是什么就可以了(只用考虑其中两种情况,因为对于剩下情况的已经考虑过了). 这里学到了一个新操作,一般的想法染色找方案都是建立反图之后top-sort一下.但是如果是对偶图,满足所属强连通分量小的在反图拓扑图上的拓扑序越大(优先涂色).那么就判以下就可以了.
#include<stdio.h>
#include<iostream>
#include<cstdio>

using namespace std;
const int maxn = 4e5 + 5;
int n,d,m;
char ss[maxn];
struct node{
	int i,j; char hi,hj;
}xj[maxn];
int tot;
int st[15],tp;
int en[maxn],nt[maxn],la[maxn],owo;
void adg(int x,int y) {
	en[++owo] = y; nt[owo] = la[x]; la[x] = owo;
}
int dfn[maxn] , low[maxn], dfx , blo[maxn],scc;
bool inst[maxn]; int sta[maxn],top;
int dy[maxn][3];
int ANS[maxn];
void tarjan(int x) {
	low[x] = dfn[x] = ++dfx;
	sta[++top] = x; inst[x] = 1;
	for(int it=la[x];it;it=nt[it]) {
		int y = en[it];
		if(!dfn[y]) {
			tarjan(y);
			low[x] = min(low[x],low[y]);
		} else if(inst[y]) low[x] = min(low[x],dfn[y]);
	}
	if(low[x]==dfn[x]) {
		int y; ++scc;
		do{
			y = sta[top--];
			inst[y] = 0;
			blo[y] = scc;
		}while(y!=x);
	}
}
int XF(int x) {
	return x>n?x-n:x+n;
}
bool isok() {
	owo = dfx = scc = 0;
	for(int i=1;i<=n;i++) {
		int zz = 0;
		for(int j=0;j<3;j++) {
			if(ss[i]-'A'!=j&&(!zz)) dy[i][j] = i,zz=1;
			else if(ss[i]-'A'==j) dy[i][j] = -1;
			else dy[i][j] = i+n;
		}
		ANS[i] = 0;
	}
	for(int i=1;i<=tot;i++) {
		la[i] = low[i] = dfn[i] = blo[i] = 0;
	}
	for(int i=1;i<=m;i++) {
		int xx = xj[i].i; char ox = xj[i].hi;
		int yy = xj[i].j; char oy = xj[i].hj;
		if(ox==ss[xx]) continue;
		if(oy==ss[yy]) adg(dy[xx][ox-'A'],XF(dy[xx][ox-'A']));
		else {
			adg(dy[xx][ox-'A'],dy[yy][oy-'A']);
			adg(XF(dy[yy][oy-'A']),XF(dy[xx][ox-'A']));
		}
	}
	for(int i=1;i<=tot;i++) {
		if(!dfn[i]) tarjan(i);
	}
	for(int i=1;i<=n;i++) {
		if(blo[i]==blo[i+n]) return 0;
		if(blo[i]<blo[i+n])  ANS[i] = 1; else ANS[i] = 2;
	}
	for(int i=1;i<=n;i++) {
		for(int j=0;j<3;j++) {
			if(dy[i][j]==-1) continue;
			if(--ANS[i]==0) {
				putchar(j+'A');
			}
		}
	}
	return 1;
}
void dfs(int now) {
	if(now==d+1) {
		 if(isok()) exit(0);
		 return;
	}
	ss[st[now]] = 'A';
	dfs(now+1);
	ss[st[now]] = 'B';
	dfs(now+1);
}
int main() {
	scanf("%d%d",&n,&d); d = 0;
	tot = 2*n;
	scanf("%s",&ss[1]);
	for(int i=1;i<=n;i++) {
		if(ss[i]=='x') st[++d] = i;
		else ss[i] = ss[i]-'a'+'A';
	}
	scanf("%d",&m);
	for(int i=1;i<=m;i++) {
		scanf("%d %c%d %c",&xj[i].i,&xj[i].hi,&xj[i].j,&xj[i].hj);
	}
	dfs(1);
	puts("-1");
}
 
posted @ 2019-01-01 19:49  Newuser233  阅读(7)  评论(0)    收藏  举报