[笔记] 2-SAT

一定要加逆否命题啊

POJ3678

基本逻辑。
p||q=1 p为0,q必为1 !p->q !q->p
p||q=0 p为0,q必为0 p->!p q->!q
p&&q=1 p为1,q必为1 !p->p !q->q
p&&q=0 p为1,q必为0 p->!q q->!p
p^ q=1 p为0,q必为1 
  		 p为1,q必为0
p^ q=0 p为0,q必为0 !p->!q(原命题) q->p(逆否命题)
  		 p为1,q必为1 p->q(原命题) !q->!p(逆否命题)

POJ3207

平面上,一个圆,圆的边上按顺时针放着n个点。现在要连m条边,
比如a,b,那么a到b可以从圆的内部连接,也可以从圆的外部连接。
给你的信息中,每个点最多只会连接的一条边。问能不能连接这m条边,
使这些边都不相交。

Luogu P3825 [NOI2017]游戏

先把 \(a\) 赛道转化为 选 \(b\) 否则选 \(c\) ,然后就可以 \(2-SAT\) 辣。

枚举每个不确定的赛道,注意我们只用枚举两种即可,因为两种类型的赛道即可包含选所有车的情况。

\(\mathcal{O}(2^d(n+m))\)

#include<iostream>
#include<cstdio>
#include<cstring>
#define R register int
using namespace std;
namespace Luitaryi {
inline int g() { R x=0,f=1;
  register char s; while(!isdigit(s=getchar())) f=s=='-'?-1:f;
  do x=x*10+(s^48); while(isdigit(s=getchar())); return x*f;
} const int M=400010,N=200010;
int n,d,m;
char s[N],ans[N]; int pos[N];
int vr[M],nxt[M],fir[N],c[N],dfn[N],low[N],stk[N],cnt,num,top,C;
bool ins[N];
inline void add(int u,int v) 
  {vr[++cnt]=v,nxt[cnt]=fir[u],fir[u]=cnt;}
struct node {int u,v,a,b;}e[N];
inline void tarjan(int u) {
  dfn[u]=low[u]=++num;
  stk[++top]=u,ins[u]=true;
  for(R i=fir[u];i;i=nxt[i]) { 
    R v=vr[i]; 
    if(!dfn[v]) tarjan(v),low[u]=min(low[u],low[v]);
    else if(ins[v]) low[u]=min(low[u],dfn[v]);
  } if(dfn[u]==low[u]) {
    R v; ++C;
    do v=stk[top--],c[v]=C,ins[v]=false; while(u!=v);
  }
}
inline bool ck() {
  for(R i=1;i<=2*n;++i) if(!dfn[i]) tarjan(i);
  for(R i=1;i<=n;++i) {
    if(c[i]==c[i+n]) return false;
    if(c[i]<c[i+n]) ans[i]=(s[i]=='A')?'B':'A';
    else ans[i]=(s[i]=='C')?'B':'C';
  }
  for(R i=1;i<=n;++i) putchar(ans[i]);
  return true;
}
inline void main() {
  n=g(),d=g();
  scanf("%s",s+1);
  for(R i=1,t=0;i<=n;++i) {
    s[i]-=32;
    if(s[i]=='X') pos[t++]=i;
  } m=g();
  for(R i=1;i<=m;++i) 
    e[i].u=g(),e[i].a=getchar(),
    e[i].v=g(),e[i].b=getchar();
  for(R S=0,lim=1<<d,t1,t2;S<=lim;++S) {
    memset(fir,0,sizeof fir),cnt=C=top=0;
    memset(dfn,0,sizeof dfn),
    memset(low,0,sizeof low),
    memset(ins,0,sizeof ins),
    memset(low,0,sizeof low);
    for(R i=0;i<d;++i) s[pos[i]]=(S>>i&1)?'A':'B';
    for(R i=1;i<=m;++i) {
      if(e[i].a==s[e[i].u]) continue;
      if(e[i].b==s[e[i].v]) {
        if(e[i].a=='C'||(e[i].a=='B'&&s[e[i].u]=='C')) 
          add(e[i].u+n,e[i].u); //选第二组的
        else add(e[i].u,e[i].u+n);
        continue;
      }
      t1=(e[i].a=='C'||(e[i].a=='B'&&s[e[i].u]=='C'))*n;
      t2=(e[i].b=='C'||(e[i].b=='B'&&s[e[i].v]=='C'))*n;
      add(e[i].u+t1,e[i].v+t2);
      add(e[i].v-t2+n,e[i].u-t1+n);
    } if(ck()) return ;
  } printf("-1"); 
}
} signed main() {Luitaryi::main(); return 0;}

2020.01.17

posted @ 2020-01-17 10:52  LuitaryiJack  阅读(128)  评论(0编辑  收藏  举报