• 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
  • 相关阅读:
    LeetCode 32. 最长有效括号(Longest Valid Parentheses)
    LeetCode 141. 环形链表(Linked List Cycle)
    LeetCode 160. 相交链表(Intersection of Two Linked Lists)
    LeetCode 112. 路径总和(Path Sum)
    LeetCode 124. 二叉树中的最大路径和(Binary Tree Maximum Path Sum)
    LightGBM新特性总结
    sql service 事务与锁
    C#泛型实例详解
    C# 中的委托和事件(详解)
    C# DateTime日期格式化
  • 原文地址:https://www.cnblogs.com/heimao5027/p/6647712.html
Copyright © 2020-2023  润新知