题意:
在三维空间中
给定n组,每组2个三维坐标 表示n组气球的中心坐标
问:
在每组中选取一个坐标,使得选出的n个坐标 有最大的半径(气球不能相交)
问最大的半径是多少
思路:
二分半径,2-sat判可行解
因为这不能四舍五入,所以最后要去掉误差后面的小数,然后暴力求解
#include<stdio.h> #include<string.h> #include<iostream> #include<algorithm> #include<math.h> #include<queue> using namespace std; #define hash Hash #define N 1000 #define M 400000+5 #define eps 1e-6 //注意n是拆点后的大小 即 n <<= 1 N为点数(注意要翻倍) M为边数 #define max(a,b) (a>b?a:b) struct Edge{ int to, nex; }edge[M]; int head[N], edgenum; void addedge(int u, int v){ Edge E = {v, head[u]}; edge[edgenum] = E; head[u] = edgenum ++; } bool mark[N]; int Stack[N], top; void init(){ memset(head, -1, sizeof(head)); edgenum = 0; memset(mark, 0, sizeof(mark)); } bool dfs(int x){ if(mark[x^1])return false;//一定是拆点的点先判断 if(mark[x])return true; mark[x] = true; Stack[top++] = x; for(int i = head[x]; i != -1; i = edge[i].nex) if(!dfs(edge[i].to)) return false; return true; } bool solve(int n){ for(int i = 0; i < n; i+=2) if(!mark[i] && !mark[i^1]) { top = 0; if(!dfs(i)) { while( top ) mark[ Stack[--top] ] = false; if(!dfs(i^1)) return false; } } return true; } struct node{ double x,y,z; }p[N][2]; double dist(node a,node b){ return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)+(a.z-b.z)*(a.z-b.z)); } double dis[N][2][N][2]; int hash(int i, int j, bool x){ return (i*2+j)*2+1-x; } bool ok(double r, int n){ init(); int i, j, k, z; for(i = 0; i < n; i++) for(j = 0; j < 2; j++) { addedge(hash(i,j,true),hash(i,j^1,false)); addedge(hash(i,j,false),hash(i,j^1,true)); } for(i = 0; i < n; i++) for(j = 0; j < 2; j++) for(k = 0; k < n; k++)if(i!=k) for(z = 0; z < 2; z++) if(dis[i][j][k][z] < r) { addedge(hash(i,j,true),hash(k,z,false)); } return solve(n<<2); } int main(){ int i, j, n; while(~scanf("%d",&n)){ for(i = 0; i < n; i++) for(j = 0; j < 2; j++) scanf("%lf %lf %lf",&p[i][j].x,&p[i][j].y,&p[i][j].z); for(i = 0; i < n; i++) for(j = 0; j < 2; j++) for(int k = 0; k < n; k++) for(int z = 0; z < 2; z++) dis[i][j][k][z] = dist(p[i][j],p[k][z])/2.0; double ans = 0, l = 0, r = 100000000; while(l+eps<r){ double mid = (l+r)/2; if(ok(mid,n)) l = ans = mid; else r = mid; } ans *= 1000.0; ans = floor(ans); ans/=1000.0; while(!ok(ans,n))ans-=0.001; while(ok(ans+0.001,n))ans+=0.001; printf("%.3lf\n", ans); } return 0; } /* 2 1 1 1 5 5 5 1 1 1 5 5 5 */
原文:http://blog.csdn.net/acmmmm/article/details/19257593