LightOJ 1251

/**
*  题目大意为有m人候选人,n个选举人,每个人有两个选择,
*  例如(+3, -1) +3表示选第3个人, -1表示不选第一个人,
* 要求最终选举出来的结果至少符合每个人的其中一种选择
* 很明显是二分图匹配,对于候选人来说,有两种情况,被选中和不被选中
*  举个例子,假设一个人选择的是(+3, +1),那么将可以将它分为两组(-1, +3) 和 (-3, +1);
*  当选3时-1也要选,当选1时,-3也要选,
* 假设又有一个人选了(+3, -2) 那么将会变成(-3, -2) ,(2, -3) 再和上面的集合融合
*  即为(-3, -2, 1) , (-1, +3) , (2, -3)有点不太好理解,还是看代码吧……
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;

vector<int> f[16010], tmp;
bool flag[20010]; int m;

void add(int a, int b){
    //这里a ^ 1 相当于是+ 和 - 的交换,比如3^1 == 2, 2 ^ 1 == 3
    //2其实是-1, 3其实是1
    f[a ^ 1].push_back(b);
    f[b ^ 1].push_back(a);
}

bool dfs(int k){
    if(flag[k]) return true;
    if(flag[k ^ 1]) return false;
    flag[k] = true;
    tmp.push_back(k);
    for(int i = 0; i < f[k].size(); ++i)
        if( !dfs( f[k][i] ) ) return false;
    return true;
}

bool two_SAT(){
    for(int i = 1; i <= m; ++i){
        if( !flag[2 * i] && !flag[2 * i + 1]){
            tmp.clear();
            if( !dfs(2 * i) ){
                for(int j = 0; j < tmp.size(); ++j) flag[ tmp[j] ] = false;
                if( !dfs(2 * i + 1) ) return false;
            }
        }
    }
    return true;
}

int main(){
    int T, n, i, a, b;
    scanf("%d", &T);
    for(int cas = 1; cas <= T; ++cas){
        printf("Case %d: ", cas);
        scanf("%d%d", &n, &m);
        for(i = 1; i <= m; ++i){
            flag[2 * i] = flag[2 * i + 1] = false;
            f[2 * i].clear(); f[2 * i + 1].clear();
        }
        for(i = 0; i < n; ++i){
            scanf("%d%d", &a, &b);
            //这里是把+,-融合到一块了,比如-1=>2, +1=>3, -2=>4, +2=>5依此类推
            a = a > 0 ? 2 * a + 1: 2 * (-a);
            b = b > 0 ? 2 * b + 1: 2 * (-b);
            add(a, b);
        }
        if( two_SAT() ){
            tmp.clear(); puts("Yes");
            for(i = 1; i <= m; ++i)
                if( flag[2 * i + 1] ) tmp.push_back(i);
            if(tmp.size() == 0) puts("0");
            else{
                printf("%d ", tmp.size());
                for(i = 0; i < tmp.size() - 1; ++i) printf("%d ", tmp[i]);
                printf("%d
", tmp[i]);
            }
        }
        else puts("No");
    }
    return 0;
}
原文地址:https://www.cnblogs.com/yaling/p/3337409.html