题解 P3825 【[NOI2017]游戏】

题目链接

Solution [NOI2017]游戏

题目大意:有三种赛车,给定 (n) 场游戏,每场游戏要么每种赛车都可以上场,要么只有一种赛车不能上场。以及给定 (m) 个约束条件,形如如果在第 (i) 场游戏使用了 (h_i) 型赛车,那么在第 (j) 场游戏就必须使用 (h_j) 型赛车。求方案

2-SAT


分析:

首先如果 (d=0),那么每个游戏能选取的赛车只有两种,这就是一个 2-SAT 问题。

而对于 (d>0) 的情况,有一个比较 naive 的想法是直接 (3^d) 去枚举每一个能随意使用赛车的游戏的选择,这样显然是过不去的

但发现我们没有必要枚举具体选哪一种车,而是枚举不选哪一种车,然后按照 (d=0) 的方法解决。这样枚举的复杂度就降到了 (2^d)(因为选择 (AB) 或者选择 (BC) 就已经涵盖了所有的情况了)

自己实现的过程中遇到了一个小插曲,就是形如若 (a)(b) 这种限制条件,是可以推出若非 (b),则非 (a) 的。这样才能保证建图的对称性。

#include <cstdio>
#include <cctype>
#include <vector>
#include <stack>
#include <algorithm>
using namespace std;
const int maxn = 1e5 + 100;
inline int read(){
	int x = 0;char c = getchar();
	while(!isdigit(c))c = getchar();
	while(isdigit(c))x = x * 10 + c - '0',c = getchar();
	return x;
}
inline char getch(){
	char c = getchar();
	while(!isalpha(c))c = getchar();
	return c;
}
vector<int> G[maxn];
inline void addedge(int u,int v){G[u].push_back(v);}
int dfn[maxn],low[maxn],scc[maxn],instk[maxn],dfs_tot,scc_tot;
stack<int> stk;
inline void tarjan(int u){
	dfn[u] = low[u] = ++dfs_tot;
	stk.push(u),instk[u] = 1;
	for(int v : G[u])
		if(!dfn[v])tarjan(v),low[u] = min(low[u],low[v]);
		else if(instk[v])low[u] = min(low[u],dfn[v]);
	if(dfn[u] == low[u]){
		int t;
		scc_tot++;
		do{
			t = stk.top();stk.pop(),instk[t] = 0;
			scc[t] = scc_tot;
		}while(t != u);
	}
}

struct node{int i,j;char hi,hj;}tmp;
vector<node> vec;
int n,d,tot,p[maxn];
char str[maxn];

inline bool chk(const int pos,const char c){
	return toupper(str[pos]) != c;
}
inline int encode(const int pos,const char c){
	if(str[pos] == 'a')return c == 'C';
	if(str[pos] == 'b')return c == 'C';
	if(str[pos] == 'c')return c == 'B';
}
inline char decode(const int pos,const int v){
	if(str[pos] == 'a')return "BC"[v];
	if(str[pos] == 'b')return "AC"[v];
	if(str[pos] == 'c')return "AB"[v];
}
inline void clear(){
	for(int i = 1;i <= 2 * n;i++){
		dfn[i] = low[i] = scc[i] = instk[i] = 0;
		G[i].clear();
	}
	scc_tot = dfs_tot = 0;
}
inline void solve(const int mask){
	for(int i = 0;i < d;i++)str[p[i]] = "ab"[(mask >> i) & 1];
	clear();
	for(auto it : vec)
		if(chk(it.i,it.hi))
			if(chk(it.j,it.hj))addedge(it.i + n * encode(it.i,it.hi),it.j + n * encode(it.j,it.hj)),addedge(it.j + n * (1 - encode(it.j,it.hj)),it.i + n * (1 - encode(it.i,it.hi)));
			else addedge(it.i + n * encode(it.i,it.hi),it.i + n * (1 - encode(it.i,it.hi)));
	for(int i = 1;i <= 2 * n;i++)
		if(!dfn[i])tarjan(i);
	for(int i = 1;i <= n;i++)
		if(scc[i] == scc[n + i])return;
	for(int i = 1;i <= n;i++)
		putchar(decode(i,scc[i] > scc[i + n]));
	exit(0);
}
int main(){
	n = read(),d = read();
	scanf("%s",str + 1);
	for(int i = 1;i <= n;i++)
		if(str[i] == 'x')p[tot++] = i;
	const int m = read();
	for(int i = 1;i <= m;i++)
		tmp.i = read(),tmp.hi = getch(),tmp.j = read(),tmp.hj = getch(),vec.push_back(tmp);
	for(int i = 0;i < (1 << d);i++)solve(i);
	return puts("-1"),0;
}
原文地址:https://www.cnblogs.com/colazcy/p/14064165.html