Time Limit: 10000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2294 Accepted Submission(s): 769
/* HDU 3622 题意:给n对炸弹可以放置的位置(每个位置为一个二维平面上的点), 每次放置炸弹是时只能选择这一对中的其中一个点,每个炸弹爆炸 的范围半径都一样,控制爆炸的半径使得所有的爆炸范围都不相 交(可以相切),求解这个最大半径. 首先二分最大半径值,然后2-sat构图判断其可行性,对于每 两队位置(u,uu)和(v,vv),如果u和v之间的距离小于2*id,也就 是说位置u和位置v处不能同时防止炸弹(两范围相交),所以连边(u,vv) 和(v,uu),求解强连通分量判断可行性. 注意精度问题 */ #include<stdio.h> #include<algorithm> #include<string.h> #include<iostream> #include<math.h> using namespace std; const int MAXN=210; const int MAXM=40005;//边的最大数 const double eps=1e-5; struct Edge { int to,next; }edge1[MAXM],edge2[MAXM]; int head1[MAXN]; int head2[MAXN]; int tol1,tol2; bool vis1[MAXN],vis2[MAXN]; int Belong[MAXN];//连通分量标记 int T[MAXN];//dfs结点结束时间 int Bcnt,Tcnt; void add(int a,int b)//原图和逆图都要添加 { edge1[tol1].to=b; edge1[tol1].next=head1[a]; head1[a]=tol1++; edge2[tol2].to=a; edge2[tol2].next=head2[b]; head2[b]=tol2++; } void init()//建图前初始化 { memset(head1,-1,sizeof(head1)); memset(head2,-1,sizeof(head2)); memset(vis1,false,sizeof(vis1)); memset(vis2,false,sizeof(vis2)); tol1=tol2=0; Bcnt=Tcnt=0; } void dfs1(int x)//对原图进行dfs,算出每个结点的结束时间,哪个点开始无所谓 { vis1[x]=true; int j; for(int j=head1[x];j!=-1;j=edge1[j].next) if(!vis1[edge1[j].to]) dfs1(edge1[j].to); T[Tcnt++]=x; } void dfs2(int x) { vis2[x]=true; Belong[x]=Bcnt; int j; for(j=head2[x];j!=-1;j=edge2[j].next) if(!vis2[edge2[j].to]) dfs2(edge2[j].to); } struct Point { int x,y; }s[MAXN]; double dist(Point a,Point b) { return sqrt((double)(a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); } bool ok(int n)//判断可行性 { for(int i=0;i<2*n;i++) if(!vis1[i]) dfs1(i); for(int i=Tcnt-1;i>=0;i--) if(!vis2[T[i]])//这个别写错,是vis2[T[i]] { dfs2(T[i]); Bcnt++; } for(int i=0;i<=2*n-2;i+=2) if(Belong[i]==Belong[i+1]) return false; return true; } int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); int n; double left,right,mid; while(scanf("%d",&n)!=EOF) { for(int i=0;i<n;i++) scanf("%d%d%d%d",&s[2*i].x,&s[2*i].y,&s[2*i+1].x,&s[2*i+1].y); left=0; right=40000.0; while(right-left>=eps) { mid=(left+right)/2; init(); for(int i=0;i<2*n-2;i++) { int t; if(i%2==0)t=i+2; else t=i+1; for(int j=t;j<2*n;j++) if(dist(s[i],s[j])<2*mid)//冲突了 { add(i,j^1); add(j,i^1);//注意顺序不能变的 } } if(ok(n))left=mid; else right=mid; } printf("%.2lf\n",right); } return 0; }