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

题意:

  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\n", 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

相关文章:

  • 2022-01-13
猜你喜欢
  • 2022-12-23
  • 2021-06-06
  • 2022-02-03
相关资源
相似解决方案