/*
典型的2-sat题目
二分半径
两点x,y有冲突,就把x连一条到yy(即y的对立点),y连一条到xx
然后求强联通分量,如果存在x到xx属于一个联通分量,则不符合条件
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<algorithm>
using namespace std;
const int MAXE=1000002;
const int MAX=202;
const double eps=1e-8;
struct point
{
double x,y;
}p[MAX];
double dis(point a,point b)
{
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
double Dis[MAX][MAX];
double L,R;
struct EDGE
{
int v; // 从u点出发能到达的点v
int next; // 从u点出发能到达的下一条边的编号
}edge[MAXE];
int first[MAX]; // first[u] = e:从点u出发的最后一条边的编号是e(“最后”是指最后输入)
int dfn[MAX]; // dfn[u]:节点u搜索的次序编号(时间戳)
int low[MAX];// low[u]:是u或u的子树能够追溯到的最早的栈中节点的次序号
int ins[MAX];// 是否在栈中
int scc[MAX]; // scc[i] = j:第i个点所在的强连通分量的编号 (此题可有可无)
int n;
int num; // 强连通分量的数目
int index; // 次序编号
int s[MAX];
int top,e;
int DFS(int x)
{
low[x]=dfn[x]=index++;
s[++top]=x;
ins[x]=1;
// 枚举每一条边:u-->v
for(int k=first[x];k!=-1;k=edge[k].next)
{
int v=edge[k].v;
if(dfn[v]==0)
{
DFS(v);
low[x]=min(low[x],low[v]);
}
else if(ins[v])
{
low[x]=min(dfn[v],low[x]);
}
}
// 如果节点u是强连通分量的根
if(low[x]==dfn[x])
{
int v;
num++;
do{
v=s[top--];
ins[v]=0;
scc[v]=num;
}while(v!=x);
}
return 1;
}
void init()
{
for(int i=1;i<=n;i++)
{
scanf("%lf%lf%lf%lf",&p[i].x,&p[i].y,&p[i+n].x,&p[i+n].y);
}
L=(1LL)<<36;
R=0;
for(int i=1;i<=2*n;i++)
for(int j=i+1;j<=2*n;j++)
{
Dis[i][j]=Dis[j][i]=dis(p[i],p[j]);
if(Dis[i][j]>R)
R=Dis[i][j];
if(Dis[i][j]<L)
L=Dis[i][j];
}
}
void add(int u,int v)
{
edge[e].v=v;
edge[e].next=first[u];
first[u]=e++;
}
bool check()
{
for(int i=1;i<=n;i++)
if(scc[i]==scc[i+n])
return false;
return true;
}
void solve()
{
double mid,ii,jj;
R=R/2.0;
L=L/2.0;
//cout<<L<<" "<<R<<endl;
while(R-L>eps)
{
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(first,-1,sizeof(first));
memset(ins,0,sizeof(ins));
index=1;
top=-1;
num=0;
e=0;
mid=(L+R)/2.0;
for(int i=1;i<=2*n;i++)
{
for(int j=i+1;j<=2*n;j++)
if(Dis[i][j]<2*mid)
{
if(i<=n)ii=i+n;
else ii=i-n;
if(j<=n)jj=j+n;
else jj=j-n;
add(i,jj);
//add(jj,i);
// add(ii,j);
add(j,ii);
// cout<<i<<" "<<jj<<endl;
// cout<<j<<" "<<ii<<endl;
}
}
for(int i=1;i<=2*n;i++)
{
if(dfn[i]==0)
{
DFS(i);
}
}
// cout<<num<<endl;
if(check())L=mid+eps;
else R=mid-eps;
}
printf("%.2lf\n",L);
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
init();
solve();
}
return 0;
}
hdu 3622 2-sat经典问题
最新推荐文章于 2022-06-30 23:08:18 发布