题意
传送门 POJ 2749
题解
最小化最大值问题,二分答案。若任意两个粮仓间的最大距离不能超过某个值,根据这个限制条件使用 2 − S A T 2-SAT 2−SAT 判断是否存在合法答案。定义布尔变量
x i 为 真 ⇔ 节 点 i 连 接 S 1 x_i 为真 \Leftrightarrow节点i连接S1 xi为真⇔节点i连接S1 对于记恨的两个节点,有 ¬ ( ( x i ∧ x j ) ∨ ( ¬ x i ∧ ¬ x j ) ) \lnot \big((x_i\land x_j)\lor (\lnot x_i\land\lnot x_j)\big) ¬((xi∧xj)∨(¬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)∨(¬xi∧xj));对于两个节点 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) ¬(xi∧xj)。
#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);
}