刚刚学 看到很多网上和书上有直接逐点判断的dfs暴力算法 加上今天事情特别多 看了半天
也可以用tarjan判断 这个有空在学
题意不用说了吧 就是求一个半径 n个炸弹吧 每个可以选择2个点之中的一个放 一定要选一个 比你多也不能少 以这n个点为圆心的圆不能相交
然后主要是每次二分建图
假设有(u1,u2) (v1, v2)一对 并且当前二分的半径是mid 如果 u1 和 v1的距离小于mid 那么建立u1->v2 和v1->u2 两条边
接下来就是算法了
我第一个是书上的 直接dfs的
#include <cstdio>
#include <cstring>
#include <vector>
#include <cmath>
using namespace std;
const int maxn = 110;
struct Point
{
int x;
int y;
}T[maxn][2];
int n;
vector <int> G[maxn*2];
int mark[maxn*2];
int S[maxn*2], c;
bool dfs(int x)
{
if(mark[x^1])
return false;
if(mark[x])
return true;
mark[x] = true;
S[c++] = x;
for(int i = 0; i < G[x].size(); i++)
if(!dfs(G[x][i]))
return false;
return true;
}
bool solve()
{
for(int i = 0; i < n*2; i += 2)
{
if(!mark[i] && !mark[i+1])
{
c = 0;
if(!dfs(i))
{
while(c > 0)
mark[S[--c]] = false;
if(!dfs(i+1))
return false;
}
}
}
return true;
}
double dis(Point p1, Point p2)
{
return sqrt((double)(p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));
}
bool ok(double mid)
{
for(int i = 0; i < n*2; i++)
G[i].clear();
memset(mark, 0, sizeof(mark));
for(int i = 0; i < n; i++)
{
for(int a = 0; a < 2; a++)
{
for(int j = i+1; j < n; j++)
{
for(int b = 0; b < 2; b++)
{
// printf("%lf\n", dis(T[i][a], T[j][b]));
if(dis(T[i][a], T[j][b]) < 2 * mid)
{
G[2*i+a].push_back(2*j+b^1);
G[2*j+b].push_back(2*i+a^1);
// printf("1 %lf\n", mid);
}
}
}
}
}
return solve();
}
int main()
{
while(scanf("%d", &n) != EOF)
{
double l = 0, r = 100000;
for(int i = 0; i < n; i++)
for(int j = 0; j < 2; j++)
scanf("%d %d",&T[i][j].x, &T[i][j].y);
double ans = 0;
while(fabs(l-r) > 1e-4)
{
double m = (l + r) / 2;
if(ok(m))
{
ans = m;
l = m;
}
else
r = m;
//printf("%lf\n", m);
}
printf("%.2f\n", ans);
}
return 0;
}