Robbie has cracked the game, and he has known all the candidate places of each round before the game starts. Now he wants to know the maximum score he can get with the optimal strategy.
2 1 1 1 -1 -1 -1 -1 1 2 1 1 -1 -1 1 -1 -1 1
1.41 1.00
//
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=40000;
int V,E;//点数(1) 边数
struct edge//邻接表
{
int t,w;//u->t=w;
int next;
};
int p[500];//表头节点
edge G[maxn];
int l;
void init()
{
memset(p,-1,sizeof(p));
l=0;
}
//添加边
void addedge(int u,int t,int w)//u->t=w;
{
G[l].w=w;
G[l].t=t;
G[l].next=p[u];
p[u]=l++;
}
//tarjan算法 求有向图强联通分量
int dfn[maxn],lowc[maxn];
//dfn[u]节点u搜索的次序编号,lowc[u]u或者u的子树能够追溯到的栈中的最早的节点
int belg[maxn];//第i个节点属于belg[i]个强连通分量
int stck[maxn],stop;//stck栈
int instck[maxn];//第i个节点是否在栈中
int scnt;//强联通分量
int index;
void dfs(int i)
{
dfn[i]=lowc[i]=++index;
instck[i]=1;//节点i入栈
stck[++stop]=i;
for(int j=p[i];j!=-1;j=G[j].next)
{
int t=G[j].t;
//更新lowc数组
if(!dfn[t])//t没有遍历过
{
dfs(t);
if(lowc[i]>lowc[t]) lowc[i]=lowc[t];
}//t是i的祖先节点
else if(instck[t]&&lowc[i]>dfn[t]) lowc[i]=dfn[t];
}
//是强连通分量的根节点
if(dfn[i]==lowc[i])
{
scnt++;
int t;
do
{
t=stck[stop--];
instck[t]=0;
belg[t]=scnt;
}while(t!=i);
}
}
int tarjan()
{
stop=scnt=index=0;
memset(dfn,0,sizeof(dfn));
memset(instck,0,sizeof(instck));
for(int i=1;i<=V;i++)
{
if(!dfn[i]) dfs(i);
}
return scnt;
}
//
/*
n对东西,每对只能选一个(i0或i1),不能不选。即:A or _A = 1 , A xor _A = 1
还存在一些约束关系(i0,j0),表示i0不能跟j0一起选。那需连边:
i0-> j1 如果选i0的话必须选j1
j0-> i1如果选j0的话必须选i1.
1)选a必选b a->b
2)a必选 _a->a
对这个新图求SCC,同一SCC的要么全选,要么都不选。
如果发现a,_a在同一SCC,表明矛盾了。
*/
struct Node
{
int x,y;
};
int n;//n对点
Node a[300];
double dis(Node h,Node k)
{
return sqrt(0.0+(h.x-k.x)*(h.x-k.x)+(h.y-k.y)*(h.y-k.y));
}
int main()
{
while(scanf("%d",&n)==1)
{
//i和i+n只能选一个且必须选一个
for(int i=1;i<=n;i++)
{
scanf("%d%d%d%d",&a[i].x,&a[i].y,&a[i+n].x,&a[i+n].y);
}
double l=0,r=10000000;
while(fabs(l-r)>1e-6)
{
double mid=(l+r)/2;
init();
V=2*n;
for(int i=1;i<=V;i++)
{
for(int j=i+1;j<=V;j++)//不用从1开始
{
if(dis(a[i],a[j])<=2*mid)//i,j不能共存
{
int ti,tj;
if(i<=n) ti=i+n;
else ti=i-n;
if(j<=n) tj=j+n;
else tj=j-n;
//选i只能选tj
addedge(i,tj,1);
//选j只能选ti
addedge(j,ti,1);
}
}
}
//如果i,i+n在同一个强联通分量中,则不能完成;否则可以实现
tarjan();
int flag=1;
for(int i=1;i<=n;i++)
{
if(belg[i]==belg[i+n])
{
flag=0;break;
}
}
//当半径足够小的时候是可以的
if(!flag) r=mid;
else l=mid;
}
printf("%.2lf\n",l);
}
return 0;
}