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.
//
#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;
}