首页 > 代码库 > 2-SAT入门

2-SAT入门

  大概学了一下2-SAT,写了一道模板和一道USACO

  输出一个方案的话,tarjan缩点后倒着拓扑,染色输出。

  求任何解下选哪个就得枚举每个点dfs来判断选哪个。  

HIT 1917(2-sat模板)

技术分享
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cmath>
#include<map>
#define ll long long 
using namespace std;
const int maxn=16010,inf=1e9;
struct poi{int too,pre,x;}e[maxn*10],e2[maxn*10];
int last[maxn],last2[maxn],dfn[maxn],low[maxn],col[maxn],lack[maxn],ru[maxn],rs[maxn],st[maxn],op[maxn];
int n,m,x,y,z,tot,tot2,tott,top,color,flag;
void read(int &k)
{
    int f=1;k=0;char c=getchar();
    while(c<0||c>9)c==-&&(f=-1),c=getchar();
    while(c<=9&&c>=0)k=k*10+c-0,c=getchar();
    k*=f;
}
void add(int x,int y){e[++tot].too=y;e[tot].x=x;e[tot].pre=last[x];last[x]=tot;}
void add2(int x,int y){e2[++tot2].too=y;e2[tot2].x=x;e2[tot2].pre=last2[x];last2[x]=tot2;}
int next(int x){return x&1?x+1:x-1;}
void tarjan(int x)
{
    dfn[x]=low[x]=++tott;st[++top]=x;lack[x]=top;
    for(int i=last[x];i;i=e[i].pre)
    if(!dfn[e[i].too])tarjan(e[i].too),low[x]=min(low[x],low[e[i].too]);
    else if(!col[e[i].too])low[x]=min(low[x],dfn[e[i].too]);
    if(dfn[x]==low[x])for(color++;top>=lack[x];top--)col[st[top]]=color;
}
void topsort()
{
    top=0;for(int i=1;i<=color;i++)if(!ru[i])st[++top]=i;
    while(top)
    {
        int now=st[top--];
        if(!rs[now])rs[now]=1,rs[op[now]]=2;
        for(int i=last2[now];i;i=e2[i].pre)
        if(!(--ru[e2[i].too]))st[++top]=e2[i].too;
    }
}
void clr()
{
    color=top=tot=tot2=flag=0;
    memset(col,0,sizeof(col));
    memset(dfn,0,sizeof(dfn));
    memset(ru,0,sizeof(ru));
    memset(rs,0,sizeof(rs));
    memset(lack,0,sizeof(lack));
    memset(last,0,sizeof(last));
    memset(last2,0,sizeof(last2));
}
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        clr();
        for(int i=1;i<=m;i++)read(x),read(y),add(x,next(y)),add(y,next(x));
        for(int i=1;i<=2*n;i++)if(!dfn[i])tarjan(i);
        for(int i=1;i<=n;i++)if(col[i<<1]==col[next(i<<1)]){printf("NIE\n");flag=1;break;}
        else op[col[i<<1]]=col[next(i<<1)],op[col[next(i<<1)]]=col[i<<1];
        if(flag)continue;
        for(int i=1;i<=tot;i++)if(col[e[i].x]!=col[e[i].too])add2(col[e[i].too],col[e[i].x]),ru[col[e[i].x]]++;
        topsort();
        for(int i=1;i<=n;i++)if(rs[col[(i<<1)]]==1)printf("%d\n",i<<1);else printf("%d\n",next(i<<1));
    }
    return 0;
}
View Code

bzoj 2199

技术分享
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
using namespace std;
const int maxn=500010;
struct poi{int x,too,pre;}e[maxn],e2[maxn];
int n,m,t,tot,tot2,tott,top,color;
int dfn[maxn],low[maxn],col[maxn],last[maxn],last2[maxn],v[maxn],st[maxn],lack[maxn];
char ans[maxn];
void read(int &k)
{
    int f=1;k=0;char c=getchar();
    while(c<0||c>9)c==-&&(f=-1),c=getchar();
    while(c<=9&&c>=0)k=k*10+c-0,c=getchar();
    k*=f;   
}
int readd()
{
    int x;read(x);char c=getchar();
    while(c!=Y&&c!=N)c=getchar(); 
    if(c==Y)return (x<<1)^1;
    return x<<1;
}
void add(int x,int y){e[++tot].too=y;e[tot].x=x;e[tot].pre=last[x];last[x]=tot;}
void add2(int x,int y){e2[++tot2].too=y;e2[tot2].x=x;e2[tot2].pre=last2[x];last2[x]=tot2;}
void dfs(int x)
{
    v[x]=t;
    for(int i=last2[x];i;i=e2[i].pre)
    if(v[e2[i].too]!=t)dfs(e2[i].too);
}
bool check(int x)
{
    t++;dfs(x);
    for(int i=1;i<=n;i++)
    if(v[col[(i<<1)^1]]==t&&v[col[i<<1]]==t)return 0;
    return 1;
}
void tarjan(int x)
{
    dfn[x]=low[x]=++tott;st[++top]=x;lack[x]=top;
    for(int i=last[x];i;i=e[i].pre)
    if(!dfn[e[i].too])tarjan(e[i].too),low[x]=min(low[x],low[e[i].too]);
    else if(!col[e[i].too])low[x]=min(low[x],dfn[e[i].too]);
    if(dfn[x]==low[x])for(color++;top>=lack[x];top--)col[st[top]]=color;
}
void dfss(int x)
{
    v[x]=1;
    for(int i=last[x];i;i=e[i].pre)
    if(!v[e[i].too])dfss(e[i].too);
}
int main()
{
    read(n);read(m);
    for(int i=1;i<=m;i++)
    {
        int x=readd(),y=readd();
        add(x^1,y);add(y^1,x);
    }
    for(int i=2;i<=((n<<1)^1);i++)if(!dfn[i])tarjan(i);
    for(int i=1;i<=n;i++)if(col[(i<<1)^1]==col[i<<1]){puts("IMPOSSIBLE");return 0;}
    for(int i=1;i<=tot;i++)if(col[e[i].x]!=col[e[i].too])add2(col[e[i].x],col[e[i].too]);
    for(int i=1;i<=n;i++)
    {
        int x=check(col[(i<<1)^1]),y=check(col[i<<1]);
        if(!(x||y)){puts("IMPOSSIBLE");return 0;}
        else if(x&&y)ans[i]=?;
        else if(x)ans[i]=Y;
        else if(y)ans[i]=N;
    }
    for(int i=1;i<=n;i++)putchar(ans[i]);
}
View Code

 

2-SAT入门