http://acm.hdu.edu.cn/showproblem.php?pid=3622
题意:
给定n个回合,每个回合给你两个点,每个回合只能选择一个点放置炸弹,在n个回合里选出n个点放置炸弹,炸弹的爆炸范围是一个圆形范围,半径可以控制。求满足每个炸弹爆炸的圆形区域不相交的条件下,的所有半径里面的最小半径最大值。
思路:
二分枚举两点之间的距离,如果存在两点距离小于等于枚举的距离时,则表示这两个点之间存在矛盾(i->j),然后根据2-sat构图方法建图,i->j' , j' -> i , j - >i' , i '->j然会通过2-sat判断是否满足条件,如果存在矛盾说明枚举的距离太小,如果不存在说明没机的距离太大....
//#pragma comment(linker,"/STACK:327680000,327680000") #include <iostream> #include <cstdio> #include <cmath> #include <vector> #include <cstring> #include <algorithm> #include <string> #include <set> #include <functional> #include <numeric> #include <sstream> #include <stack> #include <map> #include <queue> #define CL(arr, val) memset(arr, val, sizeof(arr)) #define ll long long #define inf 0x7f7f7f7f #define lc l,m,rt<<1 #define rc m + 1,r,rt<<1|1 #define pi acos(-1.0) #define ll long long #define L(x) (x) << 1 #define R(x) (x) << 1 | 1 #define MID(l, r) (l + r) >> 1 #define Min(x, y) (x) < (y) ? (x) : (y) #define Max(x, y) (x) < (y) ? (y) : (x) #define E(x) (1 << (x)) #define iabs(x) (x) < 0 ? -(x) : (x) #define OUT(x) printf("%I64d\n", x) #define lowbit(x) (x)&(-x) #define Read() freopen("din.txt", "r", stdin) #define Write() freopen("dout.txt", "w", stdout); #define N 207 using namespace std; const double eps = 1e-6; struct point { double x,y; }pt[N]; double dis[N][N]; int mat[N][N]; int dfn[N],low[N]; int belong[N],stk[N]; bool isn[N]; int cnt,idx,top; int n; int dblcmp(double x) { if (x > eps) return 1; else if (x < -eps) return -1; else return 0; } double getR(int i,int j) { double x = pt[i].x - pt[j].x; double y = pt[i].y - pt[j].y; return x*x + y*y; } void build(double mid) { int i,j; CL(mat,0); for (i = 0; i < 2*n; ++i) { isn[i] = false; low[i] = dfn[i] = -1; belong[i] = 0; for (j = 0; j < 2*n; ++j) { if (i == j) continue; if (dis[i][j] <= mid*mid)//存在矛盾的点建图 { if (j%2 == 0) { mat[i][j + 1] = 1; // mat[j + 1][i] = 1; } else { mat[i][j - 1] = 1; // mat[j - 1][i] = 1; } if (i%2 == 0) { mat[j][i + 1] = 1; // mat[i + 1][j] = 1; } else { mat[j][i - 1] = 1; //mat[i - 1][j] = 1; } } } } idx = top = cnt = 0; } void tarjan(int i) { int j; dfn[i] = low[i] = ++idx; stk[++top] = i; isn[i] = true; for (j = 0; j < 2*n; ++j) { if (mat[i][j]) { if (dfn[j] == -1) { tarjan(j); low[i] = min(low[i],low[j]); } else if (isn[j]) { low[i] = min(low[i],dfn[j]); } } } if (dfn[i] == low[i]) { ++cnt; do { j = stk[top--]; isn[j] = false; belong[j] = cnt; }while (j != i); } } bool solve(double mid) { int i; build(mid); //tarjan缩点 for (i = 0; i < 2*n; ++i) { if (dfn[i] == -1) tarjan(i); } //2-sat判断是否存在矛盾 for (i = 0; i < n; ++i) { if (belong[2*i] == belong[2*i + 1]) return false; } return true; } int main() { //Read(); int i,j; while (~scanf("%d",&n)) { for (i = 0; i < 2*n; ++i) scanf("%lf%lf",&pt[i].x,&pt[i].y); // for (i = 0; i < 2*n; ++i) printf("%d %lf %lf\n",i,pt[i].x,pt[i].y); double l = 0; double r = 0; for (i = 0; i < 2*n; ++i) { for (j = 0; j < 2*n; ++j) { if (i == j) dis[i][j] = 0; else { dis[i][j] = getR(i,j);//计算距离的平方 r = max(r,dis[i][j]); } } } //printf(">>%lf\n",r); r = sqrt(r); double ans = 0,mid = 0; while (dblcmp(l - r) < 0)//二分枚举 { mid = (l + r)/2.0; if (solve(mid)) { l = mid; ans = mid; } else { r = mid; } } printf("%.2lf\n",ans/2.0); } return 0; }