2-sat模版(完整版)

以前做过的题目,现在整理了一下,去掉了和具体题目相关的细节,并加上了一些注释,方便使用吧。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;

const int N = 1010;

int n; //原图中共有2*n个相对的节点。
int ct, depth, top, index[N<<1], d[N<<1], low[N<<1], stack[N<<1];
bool instack[N<<1], map[N<<1][N<<1], g[N<<1][N<<1];

int tot, et[N<<1], color[N<<1], op[N<<1];
bool visit[N<<1];

void initData() { //初始化数据,根据题意建图,建好的初始图为map
    ........
}

void dfs(int u) {    //tarjan求强连通分量,缩点
    int i, x;
    d[u] = low[u] = depth++;
    stack[++top] = u;
    instack[u] =true;
    for(i = 0; i < n+n; i++)
        if(map[u][i]) {
            if(d[i] == -1) {
                dfs(i);
                low[u] = min(low[u], low[i]);
            }
            else {
                if(instack[i])
                    low[u] = min(low[u], d[i]);
            }
        }
    if(low[u] == d[u]) {
        ct++;
        while(top)
        {
            x = stack[top--];
            instack[x] = false;
            index[x] = ct;
            if(x == u)  break;
        }
    }
}

void buildNewGraph() {  //根据缩点建立新图
    int i, j;
    memset(g, false, sizeof(g));
    for(i = 0; i < n+n; i++)
        for(j = 0; j < n+n; j++)
            if(map[i][j])
                g[index[i]][index[j]] = true;
    for(i = 1; i <= ct; i++)
        for(j = i+1; j <= ct; j++)
            swap(g[i][j], g[j][i]);   //将新图中的边反向
    for(i = 0; i < n; i++) {      //根据原图的矛盾节点确定新图的矛盾节点
        op[index[i]] = index[i+n];
        op[index[i+n]] = index[i];
    }
}

void transDfs(int u) {
    int i;
    visit[u] =true;
    for(i = 1; i <= ct; i++)
        if(!visit[i] && g[u][i])
            transDfs(i);
    et[++tot] = u;
}

void colorDfs(int u) {
    int i;
    color[u] = 0;
    for(i = 1; i <= ct; i++)
        if(color[i]==-1 && g[u][i])
            colorDfs(i);
}

void generateAns() {
    int i;
    memset(visit, false, sizeof(visit));
    tot = 0;
    //拓扑排序
    for(i = 1; i <= ct; i++)
        if(!visit[i])
            transDfs(i);
    memset(color, -1, sizeof(color));
    for(i = ct; i > 0; i--)
        if(color[et[i]] == -1) {
            color[et[i]] = 1;
            //选择第一个未着色的顶点x, 把x染成红色1, 并把与之矛盾的节点y及其所有子孙节点染成蓝色0。
            colorDfs(op[et[i]]);
        }
}

void solve() {
    int i;
    depth = top = ct =0;
    memset(d, -1, sizeof(d));
    memset(instack, false, sizeof(instack));
    for(i = 0; i < n+n; i++)
        if(d[i] == -1)
            dfs(i);
    for(i = 0; i < n; i++)
        if(index[i] == index[i+n])
            break;
    if(i < n)  printf("NO\n");
    else {
        printf("YES\n");
        buildNewGraph();
        generateAns();
        //printAns();
    }
}

int main()
{
    initData();
    solve();
    return  0;
}
posted @ 2012-09-23 19:59  fCarver7  阅读(166)  评论(0编辑  收藏  举报