POJ 2749 二分 + 2-SAT

neweryyy發表於2020-09-28
題意

傳送門 POJ 2749

題解

最小化最大值問題,二分答案。若任意兩個糧倉間的最大距離不能超過某個值,根據這個限制條件使用 2 − S A T 2-SAT 2SAT 判斷是否存在合法答案。定義布林變數

x i 為 真 ⇔ 節 點 i 連 接 S 1 x_i 為真 \Leftrightarrow節點i連線S1 xiiS1 對於記恨的兩個節點,有 ¬ ( ( x i ∧ x j ) ∨ ( ¬ x i ∧ ¬ x j ) ) \lnot \big((x_i\land x_j)\lor (\lnot x_i\land\lnot x_j)\big) ¬((xixj)(¬xi¬xj));對於友好的兩個節點,有 ¬ ( ( x i ∧ ¬ x j ) ∨ ( ¬ x i ∧ x j ) ) \lnot\big((x_i\land \lnot x_j) \lor (\lnot x_i \land x_j)\big) ¬((xi¬xj)(¬xixj));對於兩個節點 i , j i,j i,j 間的距離,有 i , j i,j i,j 連線 S 1 , S 2 S1,S2 S1,S2 2 × 2 2\times 2 2×2 種可能,對於節點間距離大於限制值的情況,記錄約束條件,例如 i , j i,j i,j 都連線 S 1 S1 S1,且 i , j i,j i,j 間的距離大於限制值,則有 ¬ ( x i ∧ x j ) \lnot (x_i \land x_j) ¬(xixj)

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
#define maxn 505
#define maxv 1005
#define maxd 12000005
int N, A, B, V, sx[2], sy[2];
int X[maxn], Y[maxn], ht[maxv * 2], fd[maxv * 2], dis[2][maxn], cmp[maxv];
bool used[maxv];
vector<int> G[maxv], rG[maxv], vs;

void dfs(int v)
{
    used[v] = 1;
    for (int i = 0; i < G[v].size(); i++)
    {
        int u = G[v][i];
        if (!used[u])
            dfs(u);
    }
    vs.push_back(v);
}

void rdfs(int v, int k)
{
    used[v] = 1, cmp[v] = k;
    for (int i = 0; i < rG[v].size(); i++)
    {
        int u = rG[v][i];
        if (!used[u])
            rdfs(u, k);
    }
}

int scc()
{
    vs.clear();
    memset(used, 0, sizeof(used));
    for (int v = 0; v < V; v++)
    {
        if (!used[v])
            dfs(v);
    }
    int k = 1;
    memset(cmp, 0, sizeof(cmp));
    memset(used, 0, sizeof(used));
    for (int i = vs.size() - 1; i >= 0; i--)
    {
        int v = vs[i];
        if (!used[v])
            rdfs(v, k++);
    }
    return k;
}

inline int dist(int x1, int y1, int x2, int y2)
{
    return abs(x1 - x2) + abs(y1 - y2);
}

void add_edge(int u, int v)
{
    G[u].push_back(v);
    rG[v].push_back(u);
}

bool judge(int x)
{
    for (int v = 0; v < V; v++)
    {
        G[v].clear();
        rG[v].clear();
    }
    for (int k = 0; k < A; k++)
    {
        int i = ht[k], j = ht[A + k];
        add_edge(i, N + j);
        add_edge(j, N + i);
        add_edge(N + i, j);
        add_edge(N + j, i);
    }
    for (int k = 0; k < B; k++)
    {
        int i = fd[k], j = fd[B + k];
        add_edge(i, j);
        add_edge(N + j, N + i);
        add_edge(N + i, N + j);
        add_edge(j, i);
    }
    int d12 = dist(sx[0], sy[0], sx[1], sy[1]);
    for (int i = 0; i < N; i++)
    {
        for (int j = i + 1; j < N; j++)
        {
            if (dis[0][i] + dis[0][j] > x)
            {
                add_edge(i, N + j);
                add_edge(j, N + i);
            }
            if (dis[1][i] + dis[1][j] > x)
            {
                add_edge(N + i, j);
                add_edge(N + j, i);
            }
            if (dis[0][i] + dis[1][j] + d12 > x)
            {
                add_edge(i, j);
                add_edge(N + j, N + i);
            }
            if (dis[1][i] + dis[0][j] + d12 > x)
            {
                add_edge(N + i, N + j);
                add_edge(j, i);
            }
        }
    }
    scc();
    for (int i = 0; i < N; i++)
    {
        if (cmp[i] && cmp[N + i] && cmp[i] == cmp[N + i])
            return 0;
    }
    return 1;
}

int main()
{
    scanf("%d%d%d", &N, &A, &B);
    scanf("%d%d%d%d", sx, sy, sx + 1, sy + 1);
    for (int i = 0; i < N; i++)
    {
        scanf("%d%d", X + i, Y + i);
    }
    for (int i = 0; i < A; i++)
    {
        scanf("%d%d", ht + i, ht + A + i);
        --ht[i], --ht[A + i];
    }
    for (int i = 0; i < B; i++)
    {
        scanf("%d%d", fd + i, fd + B + i);
        --fd[i], --fd[B + i];
    }
    for (int i = 0; i <= 1; i++)
    {
        for (int j = 0; j < N; j++)
        {
            dis[i][j] = dist(sx[i], sy[i], X[j], Y[j]);
        }
    }
    V = N << 1;
    int lb = -1, ub = maxd;
    while (ub - lb > 1)
    {
        int mid = (lb + ub) >> 1;
        if (judge(mid))
            ub = mid;
        else
            lb = mid;
    }
    printf("%d\n", ub == maxd ? -1 : ub);
}