zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    设计模式的分类
    设计模式工厂方法模式
    设计模式的定义
    帕斯卡命名法
    C#编写程序找一找一个二维数组中的鞍点(即该位置上的元素值在行中最大,在该 列上最小。有可能数组没有鞍点)。要求:1.二维数组的大小、数组元素的值在运行时输入;2.程序有友好的提示信息。
    设计模式抽象工厂模式
    设计模式七大原则
    理解C#中的接口
    Linux下如何查看CPU信息, 包括位数和多核信息
    关于结构体内存对齐
  • 原文地址:https://www.cnblogs.com/yaling/p/3337409.html
Copyright © 2011-2022 走看看