HDU 1848 2SAT 输出字典序最小

告诉你两两冲突的序列,让输出字典序最小。

一开始老老实实tarjan,写完了发现后面完全不能好弄,因为选了第一个点,你没办法快速找出全部对立组,只能找出本来在一个pair中的那个对立组,而找不出给定的那个随意的对立组。所以直接从1开始染色,弄不出来就染2。以此类推。

这个题还有一个教训就是,点要多开一倍,边也要多开一倍。老是忘。。。

#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<stack>
#include<cmath>
#include<cstdlib>

using namespace std;

const int MAXN=16010;

struct node
{
    int v;
    int nxt;
};
node edge[40100];//边数
int head[MAXN];
int clo[MAXN];
int dirty[MAXN],dirtop=0;
int n,m;
int cnt=0;
void add_edge(int u,int v)
{
    edge[cnt].v=v;
    edge[cnt].nxt=head[u];
    head[u]=cnt;
    cnt++;
}
int dfs(int u)
{
    clo[u]=1;
    clo[u^1]=2;
    dirty[dirtop++]=u;
    for (int i=head[u];i!=-1;i=edge[i].nxt)
    {
        int v=edge[i].v;
        if (clo[v]==1) continue;
        if (clo[v]==2||!dfs(v)) return 0;
    }
}
int solve()
{
    memset(clo,0,sizeof(clo));
    for (int i=0; i<2*n; i+=2)
    {
        if (!clo[i])
        {
            dirtop=0;
            if (!dfs(i))
            {
                for (int i=0;i<dirtop;i++) clo[dirty[i]]=clo[dirty[i]^1]=0;
                if (!dfs(i+1)) return 0;
            }
        }
    }
    return 1;
}

int main()
{
    while (scanf ("%d%d",&n,&m)!=EOF)
    {
        cnt=0;
        memset(head,-1,sizeof(head));
        while (m--)
        {
            int t1,t2;
            scanf ("%d%d",&t1,&t2);
            --t1,--t2;
            add_edge(t1,t2^1);
            add_edge(t2,t1^1);
        }
        if (!solve()) printf ("NIE\n");
        else
        {
            for (int i=0;i<2*n;i++)
            {
                if (clo[i]==1)
                {
                    printf ("%d\n",i+1);
                }
            }
        }
    }
    return 0;
}

 

posted on 2016-07-30 11:38  very_czy  阅读(419)  评论(0编辑  收藏  举报

导航