【NOI2017】游戏

醉酒当歌 提交于 2019-11-27 08:16:05

题面

https://www.luogu.org/problem/P3825

题解

我发现这些年我学的$2-sat$竟然一直是假的,醉了醉了。

我们看一下$2-sat$的形式:

如果$p$,那么$q$。

数学上学过,一个命题成立,那么它的逆否命题成立。在这里,他的逆否命题也是可以完全确定的。

所以,如果非$q$,那么非$p$。

形象理解一下,如果非$q$,那么$p$变量的值肯定不是随便取的,如果它成立,而$q$又不成立,那就假了。所以也要非$p$

所以在连边的时候,也要连它的“逆否边”。

我认为,$2-sat$是可解的,和“它的逆否命题唯一确定”的性质是很有关系的,如果只连原命题的边,解集会形成一个闭合子图的形式。。。。。。。。

#include<stack>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#define ri register int
#define N 100500
using namespace std;

int n,d,m,d1[N],t1[N],d2[N],t2[N],sani,c[N],sat[N];
int dfn[N],low[N],cnt,clo,bel[N];
bool ins[N],vis[N];
char s[N];
stack<int> sta;
vector<int> to[N];

void tarjan(int x) {
  dfn[x]=low[x]=++clo;
  sta.push(x); ins[x]=1;
  for (ri i=0;i<to[x].size();++i) {
    int y=to[x][i];
    if (dfn[y]) {
      if (ins[y]) low[x]=min(low[x],dfn[y]);
    }
    else {
      tarjan(y);
      low[x]=min(low[x],low[y]);
    }
  }
  if (low[x]==dfn[x]) {
    ++cnt;
    while (1) {
      int t=sta.top(); sta.pop();
      bel[t]=cnt; ins[t]=0;
      if (t==x) break;
    }
  }
}

int fan(int x) {
  if (x>n) return x-n; else return x+n;
}

int id(int cur,int opt) {
  if ((s[cur]=='x'&&(1<<c[cur])&sani)||s[cur]=='a') {
    if (opt==2) return cur;
    if (opt==3) return cur+n;
    if (opt==1) return -1;
  }
  if ((s[cur]=='x'&&!((1<<c[cur])&sani))||s[cur]=='b') {
    if (opt==1) return cur;
    if (opt==3) return cur+n;
    if (opt==2) return -1;
  }
  if (s[cur]=='c') {
    if (opt==1) return cur;
    if (opt==2) return cur+n;
    if (opt==3) return -1;
  }
  return -1;
}

bool dfs() {
  cnt=0; clo=0;
  for (ri i=1;i<=2*n;i++) to[i].clear();
  for (ri i=1;i<=2*n;i++) dfn[i]=low[i]=0;
  memset(ins,0,sizeof(ins));
  for (ri i=1;i<=m;i++) {
    int u=id(d1[i],t1[i]),v=id(d2[i],t2[i]);
    if (u==-1) continue;
    if (v==-1) v=fan(u);
    to[u].push_back(v);
    if (v!=fan(u)) to[fan(v)].push_back(fan(u));
  }
  for (ri i=1;i<=2*n;i++) if (!dfn[i]) tarjan(i);
  for (ri i=1;i<=n;i++) if (bel[i]==bel[i+n]) return 0;
  return 1;
}

void bfs(int x) {
  if (vis[x]) return;
  vis[x]=1;
  if (x>n) {
    int cur=x-n;
    if ((s[cur]=='x'&&(1<<c[cur])&sani) || s[cur]=='a') sat[cur]=2;
    else if ((s[cur]=='x'&&!((1<<c[cur])&sani)) || s[cur]=='b') sat[cur]=2;
    else if (s[cur]=='c') sat[cur]=1;
  }
  else {
    int cur=x;
    if ((s[cur]=='x'&&(1<<c[cur])&sani) || s[cur]=='a') sat[cur]=1;
    else if ((s[cur]=='x'&&!((1<<c[cur])&sani)) || s[cur]=='b') sat[cur]=0;
    else if (s[cur]=='c') sat[cur]=0;
  }
}

void print() {
  for (ri i=1;i<=n;i++) if (bel[i]<bel[i+n]) bfs(i); else bfs(i+n);
  for (ri i=1;i<=n;i++) putchar('A'+sat[i]);
}

int main(){
  char no[5],np[5];
  scanf("%d %d",&n,&d);
  scanf("%s",s+1);
  int cc=-1;
  for (ri i=1;i<=n;++i) if (s[i]=='x') c[i]=++cc;
  scanf("%d",&m);
  for (ri i=1;i<=m;++i) {
    scanf("%d %s %d %s",&d1[i],no,&d2[i],np);
    if (no[0]=='A') t1[i]=1;
    else if (no[0]=='B') t1[i]=2;
    else if (no[0]=='C') t1[i]=3;
    if (np[0]=='A') t2[i]=1;
    else if (np[0]=='B') t2[i]=2;
    else if (np[0]=='C') t2[i]=3;
  }
  for (sani=0;sani<(1<<d);++sani) if (dfs()) {
    print();
    return 0;
  }
  printf("-1");
  return 0;
}

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!