码迷,mamicode.com
首页 > 其他好文 > 详细

Gym 101987K TV Show Game(2-SAT)

时间:2019-10-23 09:29:26      阅读:85      评论:0      收藏:0      [点我收藏+]

标签:tac   pop   mes   class   lse   cout   top   pac   node   

题目链接: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 101987K TV Show Game(2-SAT)

标签:tac   pop   mes   class   lse   cout   top   pac   node   

原文地址:https://www.cnblogs.com/cherish-lin/p/11724087.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!