题目链接
每个城市都要在lable边的中点处,且lable要么朝下,要么朝上,很明显的2-SAT问题特征。因为每个lable的边长都要相同,且范围给定,因此可以用二分进行枚举。
分点
i2表示i城市的lable朝下,i2+1表示i城市的lable朝上,一共2n个点
建边
根据枚举的lable长度length,有三种情况:
前提是两个城市的x相差小于length,不然怎么都不会影响
1.两个城市的y相同,那么必须是一上一下
2.两个城市的y相差小于length,必须是下面的城市朝下,上面的城市朝上
3.两个城市的y相差小于2length,那么当下面的城市朝上时上面的城市必须朝上,上面的城市朝下时下面的城市也必须朝下。
在代码中实现就是:
//由于按y的大小预先进行过排序,始终有p[j].y>=p[i].y
if (p[j].y == p[i].y) //y重合,一上一下
{
addEdge(i, 1, j, 0);
addEdge(i, 0, j, 1);
addEdge(j, 1, i, 0);
addEdge(j, 0, i, 1);
}
else if (p[j].y - p[i].y < length) //只能j上i下
{
addEdge(j, 0, j, 1);
addEdge(i, 1, i, 0);
}
else if (p[j].y - p[i].y < 2 * length) //i上j上,j下i下
{
addEdge(i, 1, j, 1);
addEdge(j, 0, i, 0);
}
AC代码
//AC 16MS
//2021/10/08
#include <algorithm>
#include <iostream>
#include <string.h>
#include <vector>
#define maxn 205
using namespace std;
struct point
{
int x, y;
} p[105];
inline bool cmp(point &a, point &b) { return a.y < b.y; }
int t, n, sta[maxn], cnt;
vector<int> g[maxn];
bool vis[maxn];
void init()
{
cnt = 0;
memset(vis, false, sizeof(vis));
for (int i = 0; i < 2 * n; i++)
g[i].clear();
}
inline void addEdge(int pa, int dira, int pb, int dirb)
{
//+1表示在上
g[pa * 2 + dira].push_back(pb * 2 + dirb);
}
bool dfs(int x)
{
if (vis[x ^ 1]) return false;
if (vis[x]) return true;
vis[x] = true;
sta[cnt++] = x;
for (int i = 0; i < g[x].size(); i++)
if (!dfs(g[x][i])) return false;
return true;
}
bool check(int length)
{
init();
//加边
for (int i = 0; i < n; i++)
for (int j = i + 1; j < n; j++)
if (abs(p[i].x - p[j].x) < length)
{
//由于排过序,始终有p[j].y>=p[i].y
if (p[j].y == p[i].y) //y重合,一上一下
{
addEdge(i, 1, j, 0);
addEdge(i, 0, j, 1);
addEdge(j, 1, i, 0);
addEdge(j, 0, i, 1);
}
else if (p[j].y - p[i].y < length) //只能j上i下
{
addEdge(j, 0, j, 1);
addEdge(i, 1, i, 0);
}
else if (p[j].y - p[i].y < 2 * length) //i上j上,j下i下
{
addEdge(i, 1, j, 1);
addEdge(j, 0, 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[sta[--cnt]] = false;
if (!dfs(i + 1)) return false;
}
}
}
return true;
}
int main()
{
cin >> t;
while (t--)
{
cin >> n;
for (int i = 0; i < n; i++)
scanf("%d%d", &p[i].x, &p[i].y);
sort(p, p + n, cmp);
int l = 0, r = 20001, mid, ans = 0;
while (l < r)
{
mid = (l + r) / 2;
if (check(mid))
{
ans = mid;
l = mid + 1;
}
else
r = mid;
}
printf("%d\n", ans);
}
return 0;
}