zoukankan      html  css  js  c++  java
  • 条件转化,2-sat BZOJ 1997

    http://www.lydsy.com/JudgeOnline/problem.php?id=1997

    1997: [Hnoi2010]Planar

    Time Limit: 10 Sec  Memory Limit: 64 MB
    Submit: 1810  Solved: 684
    [Submit][Status][Discuss]

    Description

    Input

    Output

    Sample Input

    2
    6 9
    1 4
    1 5
    1 6
    2 4
    2 5
    2 6
    3 4
    3 5
    3 6
    1 4 2 5 3 6
    5 5
    1 2
    2 3
    3 4
    4 5
    5 1
    1 2 3 4 5

    Sample Output

    NO
    YES

    思路:(from 出题人):http://www.cnblogs.com/jinkun113/p/4894499.html

    如果只考虑简单的平面图判定,这个问题是非常不好做的。 
    但是题目中有一个条件——这张图存在一条哈密顿回路。
    我们把哈密顿回路在平面上画成一个圆。仔细观察一下。
    每条边如果画在圆内都是一条弦,那如果弦在圆内相交怎么办?把另一条弦翻出去。能不能两条弦都翻出去呢?不能,因为如果两条边在圆内相交,那么它们在圆外也会相交。那我们是不是就相当于就多了一个条件:这两条边不能同时在一个域内。
    所以,这张图中总共只有两个域,圆内和圆外。那么我们是不是就转化了模型:有若干个点和若干条边,你要给每个点黑白染色,使得每条边的两个端点颜色不同。直接DFS就可以了。还有个问题,边数是10^4,暴力连边会超时,但是平面图有一个定理:m<=3*n+6,那这个定理来剪枝就行了。
     
     
    然后我们只要对输入的哈密顿环进行标号,然后这样就是一个圈,假定刚开始都是在圈内,然后我们只需要判断是否在圈内就行了。

    好像我的代码因为用了map和edges这些东西,所以跑的速度比别人慢一个log= =,别人都是200ms左右,我是2000ms,人生第一次体验到了map所带来的绝望

    #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
    ")
    const int maxn = 1e5 + 5;
    struct TwoSat{
        int n, c, s[maxn * 2];
        bool mark[maxn << 1];
        vector<int> G[maxn << 1];
     
        void init(int n){
            this->n = n;
            for (int i = 0; i < 2 * n; i++) G[i].clear();
            memset(mark, false, sizeof(mark));
        }
     
        void add_edge(int x, int xval, int y, int yval){
            x = x * 2 + xval, y = y * 2 + yval;
            G[x ^ 1].pb(y), G[y ^ 1].pb(x);
        }
     
        void display(){
            for (int i = 0; i < 2 * n; i++){
                printf("from = %d
    ", i);
                for (int j = 0; j < G[i].size(); j++){
                    printf("%d ", G[i][j]);
                }
                cout << endl;
            }
        }
     
        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;
        }
     
        bool solve(){
            for (int i = 0; i < n * 2; 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, m;
    map<int, int> id;
    map<pair<int, int>, int> Point;
    vector<pair<int, int> > edges;
     
    bool test(int u1, int v1, int u2, int v2){
        if (u2 > u1 && u2 < v1 && v2 > v1) return true;
        if (u1 > u2 && u1 < v2 && v1 > v2) return true;
        return false;
    }
     
    int main(){
        int T; cin >> T;
        while (T--){
            scanf("%d%d", &n, &m);
            id.clear();
            edges.clear();
            for (int i = 0; i < m; i++){
                int u, v; scanf("%d%d", &u, &v);
                if (u > v) swap(u, v);
                edges.push_back(mk(u, v));
            }
            for (int i = 1; i <= n; i++){
                int u; scanf("%d", &u);
                id[u] = i;
            }
            if (m >= n * 3 + 6){
                puts("NO"); continue;
            }
            tar.init(m);
            for (int i = 0; i < m; i++){
                int x1 = edges[i].fi, y1 = edges[i].se;
                x1 = id[x1], y1 = id[y1];
                if (x1 > y1) swap(x1, y1);
     
                for (int j = i + 1; j < m; j++){
                    int x2 = edges[j].fi, y2 = edges[j].se;
                    x2 = id[x2], y2 = id[y2];
                    if (x2 > y2) swap(x2, y2);
                    //if (x1 == x2 || x1 == y2 || y1 == x2 || y1 == y2) continue;
                    if (test(x1, y1, x2, y2)){///假定刚开始都是在里面的
                        tar.add_edge(i, 0, j, 0);
                        tar.add_edge(i, 1, j, 1);
                    }
                }
            }
            //tar.display();
            if (tar.solve()) puts("YES");
            else puts("NO");
        }
        return 0;
    }
    View Code
  • 相关阅读:
    CMD命令提示符的基本操作指令
    JDBC连接Oracle
    JDBC连接MySQL
    Oracle树状结构的存储与展示
    C语言 深入学习
    C# widget
    C#深入多线程
    数据库常用知识
    ASP.NET开发总结
    ASP.NET —— Web Pages
  • 原文地址:https://www.cnblogs.com/heimao5027/p/6582593.html
Copyright © 2011-2022 走看看