zoukankan      html  css  js  c++  java
  • 题解 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;
    }
    
  • 相关阅读:
    【WPF/WAF】使用System.Windows.Interactivity交互事件
    【Linux/CentOS】Boolean ftp_home_dir is not defined
    【笔记】使用Token做验证
    【笔记】什么是跨域请求/访问?
    MongoDB优化与一些需要注意的细节
    MongoDB中聚合工具Aggregate等的介绍与使用
    MongoDB中MapReduce介绍与使用
    Centos下MongoDB的安装与配置
    PHP使用header方式实现文件下载
    关于redis中SDS简单动态字符串
  • 原文地址:https://www.cnblogs.com/colazcy/p/14064165.html
Copyright © 2011-2022 走看看