zoukankan      html  css  js  c++  java
  • WHU 1548 Home 2-SAT

    ---恢复内容开始---

    题意:

      N个人想回家在至少一个时刻、至多两个时刻。并且,他们每个人都能独自回家。

      定义:ai表示第i个人回家的时间, xij = abs(ai - aj) (i != j).

      在每种时间计划中,定义 y = min{xij}。

      问y最大可能是多少?

    解法:

      二分时间差的下界,用2-SAT判断是否可行。下确界即为所求。

    代码:

    这种是直接在跑的时候建边,是效率最快的  

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int MAXN = 2050;
    const int INF = (int)1e9+5;
    
    int a[MAXN];
    bool mark[MAXN];
    int S[MAXN], c;
    int n;
    
    inline int myAbs(int x) {
        return x>0 ? x : -x;
    }
    
    void init() {
        memset(mark, false, sizeof(mark));
        memset(S, 0, sizeof(S));
        c = 0;
    }
    
    bool dfs(int u, int k) {
        if (mark[u^1]) return false; //如果他的对立面和他同时被标记,那么这种情况不应该发生
        if (mark[u]) return true; //如果他已经被标记
    
        mark[u] = true; //他被标记
        S[c++] = u; //这个点入栈
        for (int i = 0; i < n*2; i++) if (u!=i && (u^1)!=i) {
            if (myAbs(a[u^1]-a[i])<k) {
                if (!dfs(i, k)) return false;
            }
        }
        return true;
    }
    
    bool check(int k) {
        init();
        for (int i = 0; i < n*2; i += 2) {
            if (!mark[i] && !mark[i|1]) { //如果这个点没有被标记
                c = 0;
                if (!dfs(i, k)) { //如果x不能赋值为真
                    while (c>0) mark[S[--c]] = false;
                    if (!dfs(i|1, k)) return false; //如果x也不能赋值为假,那么无解
                }
            }
        }
        return true;
    }
    
    void slove() {
        int l = 0, r = INF, m;
        while (l<r) {
            m = (l+r)>>1;
            if (!check(m)) r = m;
            else l = m+1;
        }
        printf("%d
    ", r-1);
    }
    
    int main() {
        #ifdef Phantom01
            freopen("WHU1548.in", "r", stdin);
        #endif // Phantom01
    
        while (scanf("%d", &n)!=EOF) {
            int k;
            for (int i = 0; i < n; i++) {
                scanf("%d %d", &k, &a[i<<1]);
                if (k&1) a[i<<1|1] = a[i<<1];
                else scanf("%d", &a[i<<1|1]);
            }
            slove();
        }
        return 0;
    }
    View Code

    下面是先建边,再跑2-SAT

    数组存邻接表(本地随机了20组数据,跑了12秒, oj跑了3秒)

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <vector>
    
    using namespace std;
    
    const int MAXN = 2050;
    const int INF = (int)1e9+5;
    
    int Edge[MAXN], next[MAXN*MAXN], to[MAXN*MAXN], used;
    int a[MAXN];
    bool mark[MAXN];
    int S[MAXN], c;
    int n;
    
    inline int myAbs(int x) {
        return x>0 ? x : -x;
    }
    
    inline void addEdge(int u, int v) {
        next[used] = Edge[u];
        to[used] = v;
        Edge[u] = used++;
    }
    
    void init() {
        memset(Edge, -1, sizeof(Edge));
        used = 0;
        memset(mark, false, sizeof(mark));
        memset(S, 0, sizeof(S));
        c = 0;
    }
    
    bool dfs(int u, int k) {
        if (mark[u^1]) return false; //如果他的对立面和他同时被标记,那么这种情况不应该发生
        if (mark[u]) return true; //如果他已经被标记
    
        mark[u] = true; //他被标记
        S[c++] = u; //这个点入栈
        for (int p = Edge[u]; p != -1; p = next[p]) if (!dfs(to[p], k))
            return false;
        return true;
    }
    
    bool check(int k) {
        init();
    
        for (int i = 0; i < n*2; i++) {
            for (int j = 0; j < i; j++) {
                if (i==j || i==(j^1)) continue;
                if (myAbs(a[i]-a[j])<k) {
                    addEdge(i^1, j);
                    addEdge(j^1, i);
                }
            }
        }
    
        for (int i = 0; i < n*2; i += 2) {
            if (!mark[i] && !mark[i|1]) { //如果这个点没有被标记
                c = 0;
                if (!dfs(i, k)) { //如果x不能赋值为真
                    while (c>0) mark[S[--c]] = false;
                    if (!dfs(i|1, k)) return false; //如果x也不能赋值为假,那么无解
                }
            }
        }
        return true;
    }
    
    void slove() {
        int l = 0, r = INF, m;
        while (l<r) {
            m = (l+r)>>1;
            if (!check(m)) r = m;
            else l = m+1;
        }
        printf("%d
    ", r-1);
    }
    
    int main() {
        #ifdef Phantom01
            freopen("WHU1548.in", "r", stdin);
        #endif // Phantom01
    
        while (scanf("%d", &n)!=EOF) {
            int k;
            for (int i = 0; i < n; i++) {
                scanf("%d %d", &k, &a[i<<1]);
                if (k&1) a[i<<1|1] = a[i<<1];
                else scanf("%d", &a[i<<1|1]);
            }
            slove();
        }
        return 0;
    }
    View Code

    下面是vector存边的(本地跑了30秒)

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <vector>
    
    using namespace std;
    
    const int MAXN = 2050;
    const int INF = (int)1e9+5;
    
    vector<int> Edge[MAXN];
    int a[MAXN];
    bool mark[MAXN];
    int S[MAXN], c;
    int n;
    
    inline int myAbs(int x) {
        return x>0 ? x : -x;
    }
    
    void init() {
        for (int i = 0; i < n*2; i++)
            Edge[i].clear();
        memset(mark, false, sizeof(mark));
        memset(S, 0, sizeof(S));
        c = 0;
    }
    
    bool dfs(int u, int k) {
        if (mark[u^1]) return false; //如果他的对立面和他同时被标记,那么这种情况不应该发生
        if (mark[u]) return true; //如果他已经被标记
    
        mark[u] = true; //他被标记
        S[c++] = u; //这个点入栈
        for (int i = 0; i < Edge[u].size(); i++) if (!dfs(Edge[u][i], k))
            return false;
        return true;
    }
    
    bool check(int k) {
        init();
    
        for (int i = 0; i < n*2; i++) {
            for (int j = 0; j < i; j++) {
                if (i==j || i==(j^1)) continue;
                if (myAbs(a[i]-a[j])<k) {
                    Edge[i^1].push_back(j);
                    Edge[j^1].push_back(i);
                }
            }
        }
    
        for (int i = 0; i < n*2; i += 2) {
            if (!mark[i] && !mark[i|1]) { //如果这个点没有被标记
                c = 0;
                if (!dfs(i, k)) { //如果x不能赋值为真
                    while (c>0) mark[S[--c]] = false;
                    if (!dfs(i|1, k)) return false; //如果x也不能赋值为假,那么无解
                }
            }
        }
        return true;
    }
    
    void slove() {
        int l = 0, r = INF, m;
        while (l<r) {
            m = (l+r)>>1;
            if (!check(m)) r = m;
            else l = m+1;
        }
        printf("%d
    ", r-1);
    }
    
    int main() {
        #ifdef Phantom01
            freopen("WHU1548.in", "r", stdin);
        #endif // Phantom01
    
        while (scanf("%d", &n)!=EOF) {
            int k;
            for (int i = 0; i < n; i++) {
                scanf("%d %d", &k, &a[i<<1]);
                if (k&1) a[i<<1|1] = a[i<<1];
                else scanf("%d", &a[i<<1|1]);
            }
            slove();
        }
        return 0;
    }
    View Code
  • 相关阅读:
    LLDB 常用的调试命令
    iOS https认证
    pod lib lint xxx.podspec 验证出错 Could not find a `ios` simulator
    LLDB 调试
    First throw call stack: 不打印方法名
    AOP
    增强现实
    2017
    iOS的主要框架介绍 (转载)
    iOS中都有什么设计模式?各个设计模式的作用 (转载)
  • 原文地址:https://www.cnblogs.com/Phantom01/p/3671300.html
Copyright © 2011-2022 走看看