Gym 101987KTV Show Game(2-SAT)

Posted cherish-lin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Gym 101987KTV Show Game(2-SAT)相关的知识,希望对你有一定的参考价值。

题目链接:https://vj.z180.cn/b4aacc08fc7aab6ce14e7baf13816c24?v=1571542994

 

题目要求n个灯(R,B),给出m组赋值方式,每一组中至少有两个是正确的,问是否能找到一组正确的赋值方式.

2-SAT模板运用强连通分量解决此类真值指派问题.

对于一组赋值: a x b y c z 来说

若a假,则bc为真

若b假,则ac为真

若c假,则ab为真

建边跑SCC(强连通分量即可)

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 1e6 + 5;
const int inf = 0x3f3f3f3f;
int dfn[maxn],low[maxn],head[maxn],belong[maxn];
//dfs序编号,最早能访问到的祖先编号,belong[i]代表i属于哪一个强连通分量
int num[maxn];//num[i]代表i这个强连通分量中有多少个元素
stack<int>sta;
int dfs_clock,cnt,scc_cnt,n,m;//DFS中的编号,边的编号,强连通分量的编号
struct node
{
  int v,next;
}e[maxn];
void add(int u,int v)
{
  e[cnt]=(node){v,head[u]};
  head[u]=cnt++;
}
void DFS(int u)
{
  sta.push(u);
  low[u]=dfn[u]=++dfs_clock;
  for(int i=head[u];i!=-1;i=e[i].next){
    int v=e[i].v;
    if(!dfn[v]){
      DFS(v);
      low[u]=min(low[u],low[v]);
    }
    else if(!belong[v]) low[u]=min(low[u],dfn[v]);
  }
  if(low[u]==dfn[u]){//以u为起点的搜索子树是一个强连通分量
    scc_cnt++;
    for(;;){
      int now=sta.top();
      sta.pop();
      belong[now]=scc_cnt;
      if(now==u)break;
    }
  }
}
int two_sat(){
  for(int i = 1;i <= 2 * n;i++){
    if(!dfn[i]){
      DFS(i);
    }
  }
  for(int i = 1;i <= n;i++){
    if(belong[i] == belong[i+n])return 0;
  }
  return 1;
}
int x,y,z,xx,yy,zz;
int main(){
  ios::sync_with_stdio(0);
  cin >> n >> m;
  for(int i = 1;i <= n * 2;i++)head[i] = -1;
  for(int i = 1;i <= m;i++){
    int a,b,c;
    char s1,s2,s3;
    cin >> a >> s1 >> b >> s2 >> c >> s3;
    if(s1 == R)x = 1;
    else x = 0;
    if(s2 == R)y = 1;
    else y = 0;
    if(s3 == R)z = 1;
    else z = 0;
    xx = x ^ 1;
    yy = y ^ 1;
    zz = z ^ 1;
    add(a + xx * n,b + y * n);
    add(a + xx * n,c + z * n);//a错,bc肯定对
    add(b + yy * n,a + x * n);
    add(b + yy * n,c + z * n);//b错,ac肯定对
    add(c + zz * n,a + x * n);
    add(c + zz * n,b + y * n);//c错,ab肯定对
  }
  int x = two_sat();
  if(x){
    for(int i = 1;i <= n;i++){
      if(belong[i] > belong[i+n])cout << R;
      else cout << B;
    }
    cout << endl;
  }
  else cout << -1 << endl;
  return 0;
}

 

以上是关于Gym 101987KTV Show Game(2-SAT)的主要内容,如果未能解决你的问题,请参考以下文章

Gym - 101438F Tree Game

GCD Guessing Game Gym - 100085G 猜数字 gcd

[Gym-101981J] Prime Game (组合计数)

Steins;Game Gym - 102798J(未解决)

Game of Cards Gym - 102822G

Gym 100827G Number Game (博弈)