UVA1146 Now or later 题解
板子。
考虑二分答案,每个点只有两种选择,并且对于任意两个点之间有一些逻辑关系。假设二分的是 ,则 表示 和 不能同时选早着陆。对于其他的也一样。
显然这是个 2-SAT 问题,直接做就可以了,复杂度平方对数。
可以使用线段树优化建图做到线性对数平方。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
using namespace std;
const int N = 4005;
int n, a[N], b[N];
vector<int> G[N];
int dfn[N], low[N], idx;
int stk[N], top;
bool in_stk[N];
int id[N], cnt;
void tarjan(int u)
{
stk[++top] = u;
dfn[u] = low[u] = ++idx;
in_stk[u] = 1;
for (auto& j : G[u])
{
if (!dfn[j])
{
tarjan(j);
low[u] = min(low[u], low[j]);
}
else if (in_stk[j])
{
low[u] = min(low[u], dfn[j]);
}
}
if (dfn[u] == low[u])
{
int y = 0;
cnt++;
do
{
y = stk[top--];
in_stk[y] = 0;
id[y] = cnt;
} while (y != u);
}
}
inline bool check(int x)
{
for (int i = 1; i <= 2 * n; i++) G[i].clear(), G[i].shrink_to_fit(), dfn[i] = low[i] = in_stk[i] = 0;
cnt = 0;
idx = 0;
top = 0;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
if (i == j) continue;
if (abs(a[i] - a[j]) < x && abs(a[i] - b[j]) < x)
{
G[i].emplace_back(i + n);
}
else
{
if (abs(a[i] - a[j]) < x)
{
G[i].emplace_back(j + n);
}
else if (abs(a[i] - b[j]) < x) G[i].emplace_back(j);
}
if (abs(b[i] - a[j]) < x && abs(b[i] - b[j]) < x)
{
G[i + n].emplace_back(i);
}
else
{
if (abs(b[i] - a[j]) < x) G[i + n].emplace_back(j + n);
else if (abs(b[i] - b[j]) < x) G[i + n].emplace_back(j);
}
}
}
for (int i = 1; i <= 2 * n; i++)
{
if (!dfn[i]) tarjan(i);
}
for (int i = 1; i <= n; i++) if (id[i] == id[i + n]) return 0;
return 1;
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0);
while (cin >> n)
{
for (int i = 1; i <= n; i++)
{
cin >> a[i] >> b[i];
}
int l = 0, r = 10000001, ans = -1;
while (l <= r)
{
int mid = l + r >> 1;
if (check(mid)) ans = mid, l = mid + 1;
else r = mid - 1;
}
cout << ans << "\n";
}
return 0;
}

浙公网安备 33010602011771号