[POI2001] 和平委员会 Peaceful Commission——2-sat(dfs构造字典序最小解)

题面

  HDU1814

解析

  2-sat裸题, 求字典序最小的解

  我一开始试图用拓扑序求字典序最小的解,YY了一阵,打完代码,无论如何都要WA,于是弃疗了,至今不知为什么会错,也许是我太菜了吧,于是学习了一下dfs构造字典序最小解的方法,时间复杂度是O(nm)的

  基本思路同拓扑序构造可行解一样,用染色法。但dfs是直接在原图中跑的,因此要传递选择的标记,也就是颜色。从小到大对每一个没有染色的点$j$尝试染上选择的颜色,在对称点$j'$(点$j$的编号小于点$j'$的编号)上染上不选的颜色,传递选择颜色时如果没有遇到不选的颜色,说明染色方案成功,否则失败,再给点$j'$染上选择的颜色 ,点$j$染上不选的颜色,进行相同操作,如果仍然失败,则说明该情况没有可行解。

  HDU上有一个坑点:多组数据。(我的英语菜得不谈,这个东西搞了我半个小时)

 代码:

#include
#include
using namespace std;
const int maxn = 8006;

int n, m, stak[maxn], top, col[maxn<<1];
vector<int> G[maxn<<1];

int mir(int x)
{
    return x&1? x+1: x-1;
}

bool paint(int x)
{
    if(col[x])
        return col[x] == 1;
    col[x] = 1;col[mir(x)] = 2;
    stak[++top] = x;
    for(unsigned int i = 0; i < G[x].size(); ++i)
    {
        int id = G[x][i];
        if(!paint(id))
            return 0;
    }
    return 1;
}

bool work()
{
    for(int i = 1; i <= (n<<1); ++i)
        if(!col[i])
        {
            top = 0;
            if(!paint(i))
            {
                while(top)  col[stak[top]] = col[mir(stak[top])] = 0, top--;
                if(!paint(mir(i)))
                    return 0;
            }
        }
    return 1;
}

int main()
{
    while(scanf("%d%d", &n, &m) != EOF)
    {
        for(int i = 1; i <= m; ++i)
        {
            int x, y;
            scanf("%d%d", &x, &y);
            G[x].push_back(mir(y));
            G[y].push_back(mir(x));
        }
        if(work())
        {
            for(int i = 1; i <= (n<<1); ++i)
                if(col[i] == 1)
                    printf("%d\n", i);
        }
        else
            printf("NIE\n");
        for(int i = 1; i <= (n<<1); ++i)
            G[i].clear(), col[i] = 0;
    }
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/Joker-Yza/p/11312672.html

你可能感兴趣的:([POI2001] 和平委员会 Peaceful Commission——2-sat(dfs构造字典序最小解))