Uvalive 3211 - Now or later(2-SAT)

题目链接 https://vjudge.net/problem/UVALive-3211

【题意】
有n架飞机需要着陆,每架飞机可以选择早着陆E或晚着陆L两种方式,必须选一种,不得在其它时间着陆。你的任务是安排这些飞机的着陆方式,使得整个计划尽量安全,也就是说把所有飞机的着陆时间升序排列后,相邻两个着陆时间间隔的最小值应尽量大。

【思路】
大白书325页例题,最小值最大化的问题可以采用二分答案的方法解决,问题转化为是否存在一个方案,使得相邻两个着陆时间间隔总是大于等于p,令x[i]表示第i架飞机是否早着陆,那么唯一的限制就是“任何小于p的两个时间差不能同时满足”,比如说Ei和Lj的时间差小于p,那么x[i]==true和x[j]==false不能同时满足,相应的满足条件也就是x[i]==false||x[j]==true。这样每一组时间差小于p的着陆时间都对应这这样一种限制条件,是一个标准的2-SAT模型。

#include<bits/stdc++.h>
using namespace std;

const int maxn = 2050;

int n;
vector<int> g[maxn * 2];
bool mark[maxn * 2];
int s[maxn * 2], top;
int t[maxn][2];

void init() {
    for (int i = 0; i < 2 * n; ++i) g[i].clear();
    memset(mark, 0, sizeof(mark));
}

void add(int x, int xval, int y, int yval) {
    x = x * 2 + xval;
    y = y * 2 + yval;
    g[x ^ 1].push_back(y);
    g[y ^ 1].push_back(x);
}

bool dfs(int u) {
    if (mark[u ^ 1]) return false;
    if (mark[u]) return true;
    s[top++] = u;
    mark[u] = true;
    for (int i = 0; i < g[u].size(); ++i) {
        if (!dfs(g[u][i])) return false;
    }
    return true;
}

bool solve() {
    for (int i = 0; i < 2 * n; i += 2) {
        if (!mark[i] && !mark[i + 1]) {
            top = 0;
            if (!dfs(i)) {
                while (top > 0) mark[s[--top]] = false;
                if (!dfs(i + 1)) return false;
            }
        }
    }
    return true;
}

bool check(int diff) {
    init();
    for (int i = 0; i < n; ++i) {
        for (int a = 0; a < 2; ++a) {
            for (int j = i + 1; j < n; ++j) {
                for (int b = 0; b < 2; ++b) {
                    if (diff > abs(t[i][a] - t[j][b])) {
                        add(i, a ^ 1, j, b ^ 1);
                    }
                }
            }
        }
    }
    return solve();
}

int main() {
    while (scanf("%d", &n) == 1) {
        int le = 0, ri = 0, mid;
        for (int i = 0; i < n; ++i) {
            scanf("%d%d", &t[i][0], &t[i][1]);
            ri = max(ri, t[i][1]);
        }
        while (le + 1 < ri) {
            mid = (le + ri) >> 1;
            if (check(mid)) le = mid;
            else ri = mid;
        }
        printf("%d\n", le);
    }
    return 0;
}
posted @ 2018-02-02 15:44  不想吃WA的咸鱼  阅读(117)  评论(0编辑  收藏  举报