zoukankan      html  css  js  c++  java
  • 2-sat Codeforces Round #403 (Div. 2, based on Technocup 2017 Finals) D

    http://codeforces.com/contest/782/problem/D

    题意:

    每个队有两种队名,问有没有满足以下两个条件的命名方法:

    ①任意两个队的名字不相同。

    ②若某个队 A 选用了第二种队名,那么如果队 B 的第一种队名和队 A 的相同,那么同样不能选择。当然,队B的第二个队名无所谓

    思路:

    学习了2-sat发现这题这么简单= =。

    如果那天A了这题就前200了

    //看看会不会爆int!数组会不会少了一维!
    //取物问题一定要小心先手胜利的条件
    #include <bits/stdc++.h>
    using namespace std;
    #pragma comment(linker,"/STACK:102400000,102400000")
    #define LL long long
    #define ALL(a) a.begin(), a.end()
    #define pb push_back
    #define mk make_pair
    #define fi first
    #define se second
    #define haha printf("haha
    ")
    /*
    另第一个名字为a,第二个名字为b
    一:
    如果ai = aj,那么只能选择第二个
    ①如果bi = bj,那么无解
    ②如果bi != bj,那么两者之间连接一条边
    上面是分类讨论
    
    二:
    如果ai != aj
    
    */
    const int maxn = 2000 + 5;
    struct TwoSAT{
        int n;
        vector<int> G[maxn * 2];
        bool mark[maxn * 2];
        int c, s[maxn * 2];///c是表示目前dfs到的个数和已经被标记的集合s
        bool dfs(int x){
            if (mark[x ^ 1]) return false;
            if (mark[x]) return true;
            mark[x] = true;
            s[c++] = x;
            for (int i = 0; i < G[x].size(); i++)
                if (!dfs(G[x][i])) return false;
            return true;
        }
    
        void init(int n){
            this->n = n;
            for (int i = 0; i < 2 * n; i++) G[i].clear();
            memset(mark, 0, sizeof(mark));
        }
        ///利用题目条件找到x和y,即假设x1[0] | x2[1] = false;即:x1[0]|!x2[1]=false
        ///那么我们反转该条件:即x1[1]|!x2[0] = true,即两者任意一个成立即为true
        ///那么我们只要交叉建图即可
        void addedge(int x, int y){
            G[x].pb(y);
        }
    
        bool solve(){
            for (int i = 0; i < 2 * n; i += 2){
                if (!mark[i] && !mark[i + 1]){
                    c = 0;
                    if (!dfs(i)){
                        while (c) mark[s[--c]] = false;
                        if (!dfs(i + 1)) return false;
                    }
                }
            }
            return true;
        }
    };
    TwoSAT tar;
    int n;
    pair<string, string> p[maxn];
    char a[100], b[100];
    
    bool solve(){
        for (int i = 0; i < n; i++){
            for (int j = i + 1; j < n; j++){
                if (p[i].fi == p[j].fi){
                    if (p[i].se == p[j].se) return false;
                    else
                        tar.addedge(i*2, i*2+1), tar.addedge(j*2, j*2+1);
                }
                else {
                    if (p[i].fi == p[j].se){
                        tar.addedge(i*2, j*2), tar.addedge(j*2+1, i*2+1);
                    }
                    if (p[i].se == p[j].fi){
                        tar.addedge(i*2+1, j*2+1), tar.addedge(j*2, i*2);
                    }
                    if (p[i].se == p[j].se){
                        tar.addedge(i*2+1, j*2), tar.addedge(j*2+1, i*2);
                    }
                }
            }
        }
        if (!tar.solve()) return false;
        puts("YES");
        for (int i = 0; i < 2 * n; i += 2){
            if (tar.mark[i]){
                cout << p[i/2].fi << endl;
            }
            else {
                cout << p[i/2].se << endl;
            }
        }
        return true;
    }
    
    int main(){
        cin >> n;
        tar.init(n);
        for (int i = 0; i < n; i++){
            scanf("%s%s", a, b);
            p[i].fi = p[i].fi + a[0] + a[1] + a[2];
            p[i].se = p[i].se + a[0] + a[1] + b[0];
        }
        if (!solve()) puts("NO");
        return 0;
    }
    View Code
  • 相关阅读:
    Solution: Win 10 和 Ubuntu 16.04 LTS双系统, Win 10 不能从grub启动
    在Ubuntu上如何往fcitx里添加输入法
    LaTeX 笔记---Q&A
    Hong Kong Regional Online Preliminary 2016 C. Classrooms
    Codeforces 711E ZS and The Birthday Paradox
    poj 2342 anniversary party
    poj 1088 滑雪
    poj 2479 maximum sum
    poj 2481 cows
    poj 2352 stars
  • 原文地址:https://www.cnblogs.com/heimao5027/p/6647712.html
Copyright © 2011-2022 走看看