题解 P3825 【[NOI2017]游戏】

貌似这道题挺妙的样子?(其实是我太弱了)

也算是一篇(2-sat)的小结吧?

(2-sat)

给定一些布尔类型,每个点只有(0/1)两种取值,然后给出多种限制条件,要求方案。

考虑把每个点拆成两个点,如:(a->a_1,a_0)

然后对于每种限制条件进行不同的连边。

以这道题为例,

我们先考虑(d = 0)的条件。

那么注意到每个点它只有两个取值,我们可以先预处理出来。

然后这就是一个(2-sat)问题。

考虑连边条件。

如果一个条件是(x)(A),则(y)(B)

但是(x)位置上的点就是(a),那么说明这种条件是无法成立的,我们忽略。

如果(x)位置上不是(a)(比如是(B)),但(y)(b),那么就有:若(x)(A),则(y)(B),但(y)不能为(B),所以(x)亦不能为(A),我们就把(x_A)连向(x_C)说明(x_A)不能取。

其他条件的话需要考虑周全,大概是这样连:

(x_A->y_B)

(y_{other} -> x_{other})(如果(y)不为(B),那么(x)亦不为(A)

这样我们就能处理(d = 0)的情况了

如果(dquad!=quad0)

因为(d)那么小,所以暴枚啊!

我们可以枚举(x)这个位置不能取那个点,这样枚举的话,如果(x)不能取(A),我们就把(B,C)存在的答案包括了进去,如果枚举(x)不能取(B),那么就把(A,C)的答案包括了进去。

所以对于每个(x)我们只要枚举(2)次。

复杂度(O(2^d*N))

#include<bits/stdc++.h>
using namespace std;
#define re register
#define rep( i, s, t ) for( re int i = s; i <= t; ++ i ) 
#define Next( i, x ) for( re int i = head[x]; i; i = e[i].next ) 
int read() {
	char cc = getchar(); int cn = 0, flus = 1;
	while(cc < '0' || cc > '9') {  if( cc == '-' ) flus = -flus;  cc = getchar();  }
	while(cc >= '0' && cc <= '9')  cn = cn * 10 + cc - '0', cc = getchar();
	return cn * flus;
}

const int N = 5e5 + 5;
int head[N], dfn[N], low[N], s[N], cnt, n, m, top, tim, col, color[N];
int stac[N], top2, d, suit[N], ch[N][2];
struct E {
	int to, next;
}e[N * 2];
struct Node{
	int x, hx, y, hy;
}q[N];
char S[N];

void add( int x, int y ) {
	e[++cnt] = (E) { y, head[x] }, head[x] = cnt;
} 
void trajan( int x ) {
	dfn[x] = low[x] = ++tim, s[++ top] = x;
	Next( i, x ) {
		int v = e[i].to;
		if( !dfn[v] )  trajan( v ), low[x] = min( low[x], low[v] );
		else if( !color[v] )  low[x] = min( low[x], dfn[v] );
	}
	if( low[x] == dfn[x] ) {
		++ col;
		while( s[top + 1] != x ) color[s[top--]] = col;
	}
} 

void doit() {
	memset( head, 0, sizeof(head) ), memset( dfn, 0, sizeof(dfn) );
	memset( low, 0, sizeof(low) ), memset( color, 0, sizeof(color) );
	cnt = tim = top = col = 0;
	rep( i, 1, m ) {
		int x = q[i].x, y = q[i].y, u = x + q[i].hx * n, v = y + q[i].hy * n;
		if( q[i].hx == suit[x] ) continue;
		if( q[i].hy == suit[y] ) {
			add( ch[x][ch[x][1] == u], ch[x][ch[x][1] != u] ); 
		}
		else add( u, v ), add( ch[y][ch[y][1] != v], ch[x][ch[x][1] != u]);
	}
	rep( i, 1, n ) {  if( !dfn[ch[i][0]] ) trajan( ch[i][0] );  if( !dfn[ch[i][1]] ) trajan( ch[i][1] );  }
	rep( i, 1, n ) if( color[ch[i][0]] == color[ch[i][1]] ) return ;
	rep(i, 1, n) {
		if( color[ch[i][0]] > color[ch[i][1]] ) printf("%c", ( ( ch[i][1] - 1 ) / n ) + 'A'  );
		else printf("%c", ( ( ch[i][0] - 1 ) / n ) + 'A' );
	}
    exit(0);
}
void dfs( int x ) {
	if( x > d ) {
		doit();
		return ;
	}
	int now = stac[x];
	suit[now] = 0, ch[now][0] = now + n, ch[now][1] = now + 2 * n,
	dfs( x + 1 );
	suit[now] = 1, ch[now][0] = now, ch[now][1] = now + 2 * n;
	dfs( x + 1 );
}
signed main()
{
	n = read(), d = read();
	scanf( "%s", S );
	int len = strlen(S);
	rep( i, 0, len - 1 ) {
		int now = i + 1;
		if( S[i] == 'x' ) stac[++top2] = now;
		if( S[i] == 'a' ) suit[now] = 0, ch[now][0] = now + n, ch[now][1] = now + 2 * n;
		if( S[i] == 'b' ) suit[now] = 1, ch[now][0] = now, ch[now][1] = now + 2 * n;
		if( S[i] == 'c' ) suit[now] = 2, ch[now][0] = now, ch[now][1] = now + n; 
	}
	m = read();
	rep( i, 1, m )
		q[i].x = read(), q[i].hx = getchar() - 'A', q[i].y = read(), q[i].hy = getchar() - 'A';
	dfs( 1 );
	printf("-1");
	return 0;
} 
原文地址:https://www.cnblogs.com/Soulist/p/10630340.html