题目大意:有N对点,给定这N对点的坐标,现在要求找出一个最大的半径R,使得可以从每对点中选择一个点,并且这N个点以自己为圆心,半径为R的圆两两不相交。
2-SAT问题解法:对于每一对点,我们且称之为“兄弟点”;对于这2*N个点,如果两个点之间“矛盾”,对于本题即两个圆相交,则连一条边。对这个图求强连通分量,然后看是否有某对点属于同一个强连通分量。如果N对点每一对都属于不同的强连通分量,满足。否则不满足。然后二分半径即可。
- #include <cstdio>
- #include <cstring>
- #include <cmath>
- #define MAXN 210
- #define EPS 1e-3
- using namespace std;
- int n;
- struct Edge{
- int v,next;
- Edge(){}
- Edge(int _v,int _next):v(_v),next(_next){}
- }edge[MAXN*MAXN];
- int head[MAXN], size;
- inline void initial(){
- memset(head,-1,sizeof(int)*(n+2));
- size = 0;
- }
- inline void add_edge(int u,int v){
- edge[size] = Edge(v,head[u]);
- head[u] = size ++;
- }
- int belong[MAXN];
- bool vis[MAXN];
- int depth;
- int bcnt;
- int dfn[MAXN], low[MAXN];
- int stack[MAXN], tail ;
- inline void Tarjan(int u){
- dfn[u] = low[u] = depth ++;
- vis[u] = 1;
- stack[++tail] = u;
- for(int i = head[u];i != -1;i = edge[i].next){
- int v = edge[i].v;
- if(dfn[v] == -1){
- Tarjan(v);
- if(low[u] > low[v])
- low[u] = low[v];
- }else if(vis[v] && low[u] > dfn[v]){
- low[u] = dfn[v];
- }
- }
- if(low[u] == dfn[u]){
- bcnt ++;
- int j;
- do{
- j = stack[tail--];
- vis[j] = 0;
- belong[j] = bcnt;
- }while(j != u);
- }
- }
- double x[MAXN], y[MAXN];
- inline double Cal(int i,int j){
- return (x[i]-x[j])*(x[i]-x[j]) + (y[i]-y[j])*(y[i]-y[j]);
- }
- inline bool can(){
- int N = n/2;
- for(int i = 1;i <= N; ++i)
- if(belong[i] == belong[i+N]) return false;
- return true;
- }
- int main()
- {
- int N;
- while(scanf("%d",&N) != EOF){
- n = 2*N;
- for(int i = 1;i <= N; ++i)
- scanf("%lf%lf%lf%lf",&x[i],&y[i],&x[i+N],&y[i+N]);
- double right = 10000.0*10000.0, left = 0.0, mid;
- while(right - left >= EPS){
- mid = (right + left)/2.0;
- initial();
- for(int i = 1;i < n; ++i)
- for(int j = i + 1;j <= n; ++j){
- //if(i + N == j) continue;
- if(Cal(i,j) < mid){
- int u, v;
- if(i <= N) u = i + N;
- else u = i - N;
- if(j <= N) v = j + N;
- else v = j - N;
- add_edge(i,v);
- add_edge(j,u);
- }
- }
- tail = depth = bcnt = 0;
- memset(vis,0,sizeof(bool)*(n+2));
- memset(dfn,-1,sizeof(int)*(n+2));
- memset(low,0,sizeof(int)*(n+2));
- for(int i = 1;i <= n; ++i)
- if(dfn[i] == -1) Tarjan(i);
- if(can()) left = mid;
- else right = mid;
- }
- printf("%.2lf/n",sqrt(left)/2.0);
- }
- }