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<iostream>
#include<cstdio>
#include<vector>
#include<cstring>

using namespace std;

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

const int maxn=8005;

int n,m;
vector<int>e[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<e[x].size();i++){
        if(!paint(e[x][i])){
            return false;
        }
    }
    return true;
}

bool work()
{
    memset(col,0,sizeof(col));
    for(int i=1;i<=2*n;i+=2){
        if(col[i]||col[oth(i)]){
            continue;
        }
        cnt=0;
        if(!paint(i)){
            for(int j=1;j<=cnt;j++){
                col[ans[j]]=col[oth(ans[j])]=0;
            }
            if(!paint(oth(i))){
                return false;
            }
        }
    }
    return true;
}

int main()
{
    while(scanf("%d%d",&n,&m)!=EOF){
        for(int i=1;i<=2*n;i++){
            e[i].clear();
        }
        int u,v;
        for(int i=1;i<=m;i++){
            scanf("%d%d",&u,&v);
            e[u].push_back(oth(v));
            e[v].push_back(oth(u));
        }
        if(work()){
            for(int i=1;i<=2*n;i++){
                if(col[i]==1){
                    printf("%d\n",i);
                }
            }
        }else{
            printf("NIE\n");
        }
    }
    return 0;
}

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


#include<iostream>
#include<cstdio>
#include<cstring>

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<m;i++){
            scanf("%d%d",&u,&v);
            u--;v--;
            add_edge(u,v^1);
            add_edge(v,u^1);
        }
        if(twosat()){
            for(int i=0;i<2*n;i+=2){
                if(mark[i]){
                    printf("%d\n",i+1);
                }else{
                    printf("%d\n",i+2);
                }
            }
        }else{
            printf("NIE\n");
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zhouzi2018/article/details/81699678
今日推荐