Peaceful Commission HDU - 1814 (2-SAT)(输出最小字典序)

传送门

题意:就是有n党派,每个党派两个人,只能够从中选择一个人进入委员会。同时,有m组关系,表示某两个人不能够同时出现在委员会中。求出字典序最小的委员会名单。

题解:一个2-sat问题,因为要求出最小字典序,只能够用最暴力的方法,时间复杂度为O(nm)。 

通过2-sat问题构图
1.首先对当前点x进行染色,染为可行,其党派内的对应结点x’则染为不可行。 
2.访问所有和x相连的结点vi,依次进行搜索。 
3.如果vi未被染过颜色,同x的染色一样继续进行。如果vi已经被染过色,那么检查它是否可行。如果产生了矛盾,则证明当前染色是错误的,需退回将x’染为可行,x不可行(即重新对x’进行搜索,work()函数中的Paint(Oth(x))语句的含义 )。 
4.如果重新尝试染Paint(x’)也不行,则意味着无解,退出函数并输出,否则继续依次尝试染色。 
5.如果所有结点都被染上了颜色,程序结束,访问所有结点,输出所有被染为可行的结点 

代码一:使用vector+染色判断


#include
#include
#include
#include

using namespace std;

#define oth(x) (x%2==0?x-1:x+1)

const int maxn=8005;

int n,m;
vectore[maxn*2];
int col[maxn*2];
int cnt,ans[maxn*2];

bool paint(int x)
{
    if(col[x]!=0){
        return col[x]%2;
    }
    col[x]=1;col[oth(x)]=2;
    ans[++cnt]=x;
    for(int i=0;i

代码二:使用链式前向星+染色判断


#include
#include
#include

using namespace std;

const int maxn=8010*2;
const int maxm=80010;

struct edge{
    int to,next;
};
edge edges[maxm<<1];
int head[maxn],tot;

void add_edge(int u,int v)
{
    edges[tot].to=v;
    edges[tot].next=head[u];
    head[u]=tot++;
}

int n,m;
int cnt,s[maxn];
bool mark[maxn];

bool dfs(int u)
{
    if(mark[u^1]){
        return false;
    }
    if(mark[u]){
        return true;
    }
    s[cnt++]=u;
    mark[u]=1;
    for(int i=head[u];~i;i=edges[i].next){
        if(!dfs(edges[i].to)){
            return false;
        }
    }
    return true;
}

bool twosat()
{
    memset(mark,0,sizeof(mark));
    for(int i=0;i<2*n;i+=2){
        if(!mark[i]&&!mark[i+1]){
            cnt=0;
            if(!dfs(i)){
                while(cnt){
                    mark[s[--cnt]]=false;
                }
                if(!dfs(i^1)){
                    return false;
                }
            }
        }
    }
    return true;
}

int main()
{
    while(scanf("%d%d",&n,&m)!=EOF){
        tot=0;
        memset(head,-1,sizeof(head));
        int u,v;
        for(int i=0;i

 

你可能感兴趣的:(2-sat)