2-SAT求任意解模板

int stk[N],vis[N],low[N],link[N],mark[N];
int top,index,id,du[N];//记录入度数
int pre[N],cnt,g[N];// g 用来记录topsort后的结果
int g1[N]; //用来记录缩点后的每一个点所含的点


void dfs(int s)
{
    mark[s]=1;
    vis[s]=index++;
    low[s]=vis[s];
    stk[top++]=s;
    for(int p=pre[s];p!=-1;p=edge[p].next)
    {
        int v=edge[p].to;
        if(mark[v]==0) dfs(v);
        if(mark[v]==1) low[s]=min(low[s],low[v]);
    }
    if(low[s]==vis[s])
    {
        int tmp;
        id++;
        do
        {
            tmp=stk[top-1];
            link[tmp]=id;
            mark[tmp]=-1;
        }while(stk[--top]!=s);
    }
}

void add_edge(int u,int v)
{
    edge[cnt].from=u;
    edge[cnt].to=v;
    edge[cnt].next=pre[u];
    pre[u]=cnt++;
}

void topsort()
{
    memset(mark,0,sizeof(mark));
    top=0;
    int tcnt=0;
    for(int i=1;i<=id;i++)
        if(du[i]==0)
        {
            mark[i]=1;
            stk[top++]=i;//把这个节点入栈
            g[tcnt++]=i;
        }
    while(top!=0)
    {
        int cur=stk[--top];
        for(int p=pre[cur];p!=-1;p=edge[p].next)
        {
            int v=edge[p].to;
            if(mark[v]==1) continue;
            du[v]--;
            if(du[v]==0)
            {
                mark[v]=1;
                stk[top++]=v;
                g[tcnt++]=v;
            }
        }
    }

}

void dfs1(int s) //将所有不可能的情况标记
{
    mark[s]=-1;
    for(int p=pre[s];p!=-1;p=edge[p].next)
    {
        int v=edge[p].to;
        dfs1(v);
    }
}

void sat2(int sn) //top 表示传入的点数。 其中要保证标号从0开始而且0和1是一组
{
    top=index=id=0;
    memset(mark,0,sizeof(mark));
    for(int i=0;i<sn;i++)
        if(mark[i]==0)
            dfs(i);
    int flag=0;
    for(int i=0;i<sn;i+=2)
    {
        if(link[i]==link[i+1])
        {
            flag=1;
            break;
        }
    }
    if(flag)
    {
        /*  当不可行的时候输出 */
        printf("bad luck\n");
    }
    else
    {
        /*  可行的时候输出 */
        printf("YES\n");

        int tcnt=cnt;
        memset(g1,0,sizeof(g1));
        cnt=0;
        memset(pre,-1,sizeof(pre));
        for(int i=0;i<sn;i++)
        {
            g1[ link[i] ]=i;
        }

        memset(du,0,sizeof(du));

        for(int i=0;i<tcnt;i++)
        {
            int x=edge[i].from;
            int y=edge[i].to;
            if(link[x] != link[y])
            {
                add_edge(link[y],link[x]);//建逆图
                du[ link[x] ]++;
            }
        }
        topsort();
        memset(mark,0,sizeof(mark));

        for(int i=0;i<id;i++)
        {
            if(mark[ g[i] ]!=-1)//表示这个点可以选
            {
                mark[ g[i] ]=1;
                int key=g1[ g[i] ];
                key=key^1;
                key=link[key];
                dfs1(key);
            }
        }
        /*   print  mark[ link[i] ]==1 的表示可选的 */
        
    }
}

 

posted @ 2013-10-03 17:14  chenhuan001  阅读(351)  评论(0编辑  收藏  举报