CodeForces776D The Door Problem

题意:给n个门的状态,0关1开,接下来是m个开关,每个门最多由两个开关控制,每个开关可以开多次,求最后能不能使得所有开关变成开的状态

题解:一个开关开两次或以上就没有意义,所以开关只能开1次或者不开,也就是两个状态,0门的两个开关只能开一个,1门两个开关都开或者都关,这个问题就可以抽象成2-sat问题

#include <bits/stdc++.h>
#define maxn 100005
using namespace std;
int a[maxn];
vector<int >b[maxn];
struct TwoSAT {
  int n;
  vector<int> G[maxn*2];
  bool mark[maxn*2];
  int S[maxn*2], c;

  bool dfs(int x) {
    if (mark[x^1]) return false;
    if (mark[x]) return true;
    mark[x] = true;
    S[c++] = x;
    for (int i = 0; i < G[x].size(); i++)
      if (!dfs(G[x][i])) return false;
    return true;
  }

  void init(int n) {
    this->n = n;
    for (int i = 0; i < n*2; i++) G[i].clear();
    memset(mark, 0, sizeof(mark));
  }
//x = xval && y = yval 
  void add_clause(int x, int xval, int y, int yval) {
    x = x * 2 + xval;
    y = y * 2 + yval;
    G[x].push_back(y);
    G[y].push_back(x);
  }

  bool solve() {
    for(int i = 2; i <= n*2; i += 2)
      if(!mark[i] && !mark[i+1]) {
        c = 0;
        if(!dfs(i)) {
          while(c > 0) mark[S[--c]] = false;
          if(!dfs(i+1)) return false;
        }
      }
    return true;
  }
}mmp;
int main(){
    int n,m,T,t1,t2;
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=m;i++){
        cin>>T;
        while(T--){
            cin>>t1;
            b[t1].push_back(i);
        }
    }
    mmp.init(m);
    for(int i=1;i<=n;i++){
        if(a[i] == 0){
            mmp.add_clause(b[i][0], 0, b[i][1], 1);
            mmp.add_clause(b[i][0], 1, b[i][1], 0);
        }
        else{
            mmp.add_clause(b[i][0], 1, b[i][1], 1);
            mmp.add_clause(b[i][0], 0, b[i][1], 0);
        }
    }
    cout<<(mmp.solve()?"YES":"NO")<<endl;
    return 0;
}
View Code

 

posted on 2017-07-14 15:59  2855669158  阅读(149)  评论(0编辑  收藏  举报

导航