题目链接
一个谷仓要么连S1,要么连S2,很显然是2-SAT问题。
建边:
先把hate和friend关系的边建好。
然后枚举一个最远距离k,比较每个谷仓与其他谷仓的距离(两个谷仓分别连接S1S1,S1S2,S2S1,S2S2四种情况),如果超过了k就建边。
AC代码:
//AC 625MS
//2021/10/09
#include <cmath>
#include <cstdio>
#include <cstring>
#include <vector>
#define maxn 1005
using namespace std;
struct point
{
int x, y;
} p[maxn], s1, s2;
int n, a, b, ds;//ds为S1和S2的距离
int stack[maxn], cnt = 0;
int h1[maxn], h2[maxn], f1[maxn], f2[maxn], dist1[maxn], dist2[maxn];//dist1表示谷仓到S1的距离
bool vis[maxn];
vector<int> g[maxn];
inline int manhattan(point &a, point &b) { return abs(a.x - b.x) + abs(a.y - b.y); }
inline void addEdge(int x, int xv, int y, int yv) { g[x * 2 + xv].push_back(y * 2 + yv); }
void init()
{
memset(vis, false, sizeof(vis));
for (int i = 0; i < maxn; i++)
g[i].clear();
}
bool dfs(int x)
{
if (vis[x ^ 1]) return false;
if (vis[x]) return true;
vis[x] = true;
stack[cnt++] = x;
for (int i = 0; i < g[x].size(); i++)
if (!dfs(g[x][i])) return false;
return true;
}
bool check(int x)
{
init();
for (int i = 0; i < a; i++) //添加hate关系
{
addEdge(h1[i], 1, h2[i], 0);
addEdge(h1[i], 0, h2[i], 1);
addEdge(h2[i], 1, h1[i], 0);
addEdge(h2[i], 0, h1[i], 1);
}
for (int i = 0; i < b; i++) //添加friend关系
{
addEdge(f1[i], 1, f2[i], 1);
addEdge(f1[i], 0, f2[i], 0);
addEdge(f2[i], 1, f1[i], 1);
addEdge(f2[i], 0, f1[i], 0);
}
//将每头牛和其他的牛进行比较,进行建边
for (int i = 0; i < n; i++)
{
for (int j = i + 1; j < n; j++)
{
//四种连接情况,连接在不同的点上时需要加上S1到S2的距离
//s1,s1
if (dist1[i] + dist1[j] > x)
{
addEdge(i, 0, j, 1);
addEdge(j, 0, i, 1);
}
//s1,s2
if (dist1[i] + ds + dist2[j] > x)
{
addEdge(i, 0, j, 0);
addEdge(j, 1, i, 1);
}
//s2,s1
if (dist2[i] + ds + dist1[j] > x)
{
addEdge(i, 1, j, 1);
addEdge(j, 0, i, 0);
}
//s2,s2
if (dist2[i] + dist2[j] > x)
{
addEdge(i, 1, j, 0);
addEdge(j, 1, i, 0);
}
}
}
for (int i = 0; i < n * 2; i += 2)
{
if (!vis[i] && !vis[i + 1])
{
cnt = 0;
if (!dfs(i))
{
while (cnt > 0)
vis[stack[--cnt]] = false;
if (!dfs(i + 1)) return false;
}
}
}
return true;
}
int main()
{
scanf("%d%d%d", &n, &a, &b);
scanf("%d%d%d%d", &s1.x, &s1.y, &s2.x, &s2.y);
ds = manhattan(s1, s2);
for (int i = 0; i < n; i++)
{
scanf("%d%d", &p[i].x, &p[i].y);
dist1[i] = manhattan(s1, p[i]);
dist2[i] = manhattan(s2, p[i]);
}
for (int i = 0; i < a; i++)
{
scanf("%d%d", &h1[i], &h2[i]);
h1[i]--;
h2[i]--;
}
for (int i = 0; i < b; i++)
{
scanf("%d%d", &f1[i], &f2[i]);
f1[i]--;
f2[i]--;
}
int l = 0, r = 4000005, mid, ans = 0;
while (l < r)
{
mid = (l + r) / 2;
if (check(mid))
{
r = mid;
ans = mid;
}
else
l = mid + 1;
}
//需要判断是否有解
printf("%d", r == 4000005 ? -1 : ans);
return 0;
}