CSU 2068 pacnw2012

2068: Ritual Circle

Submit Page      Summary      Time Limit: 60 Sec       Memory Limit: 512 Mb       Submitted: 2       Solved: 1    

Description

Before the departure of the Fellowship from Rivendell, Bilbo gave Frodo his Elvish-made sword that he called Sting. This sword was special: the blade would glow blue whenever Orcs were close.

Input

The input will contain multiple test cases. Each test case will consist of two sets of points in the plane representing the positions of Frodo’s companions and the enemy Orcs, respectively. All of these points will be represented by integer coordinates with component values between 0 and 100 inclusive. Every point in each case will be unique. The total number of points from both sets (Frodo’s companions and the Orcs) in any single problem instance will be at most 300, and there will be at most 10 test cases with more than 200 points.

Output

Frodo needs to determine the radius of the smallest circle that contains all of the points of his com- panions’ positions, and excludes all of the points of the Orcs’ positions. Whenever such a circle does not exist, then the sword Sting glows blue and Frodo is danger, so print “The Orcs are close”. If such a circle does exist, print the radius of the smallest such circle given as a decimal value that is within a relative error of 1e-7. In the first example, no circle is possible that includes both companions but excludes both Orcs; any such circle would need to have a radius of at least 1/2, but any circle that large would need to include at least one of the Orcs. In the third example, a circle may be placed with its center an infinitesimally small distance away from (1/2,1/2) in a direction toward the point (0,1), with a radius that is infinitesimally larger than 1/2. The fourth example is a degenerate case with only one companion, in which case a circle of zero radius works.

Sample Input

Companions: (0,0) (1,1)
Orcs: (1,0) (0,1)
Companions: (0,0) (0,1) (1,1) (1,0)
Orcs: none
Companions: (0,0) (0,1) (1,1)
Orcs: (1,0)
Companions: (0,0)
Orcs: none

Sample Output

The Orcs are close
0.707106781186548
0.707106781186548
0

Hint

Source

pacnw2012


题目大意:有两类点A和B,每一类有多个点,现要求画一个圆,A类点全在圆内,B类点全在圆外,问最小半径。

题解:

这个圆一点是经过2个及以上的给出的点(无论A和B)。再经过简单画图可以看出,一定会至少经过2个A类的点,因为我们可以不断缩圈直到经过2个A类的点,但3个就不一定了,因为B类点的限制可能有这种情况


但是,上图的情况我们可以理解为圆是由圆上的3点(2个A,1个B)构成的,然后向如图方向“推一下”,使B类点到圆外。


所以我们的思路大致为,暴力枚举3个点构成的圆,判断是否符合要求:圆外没有A类点,圆内没有B类点,圆上呢?

圆上的点就比较复杂了。

首先,如果圆上仅有A类点,可以,因为可以扩圈无穷小。如果仅有B类点呢?看图


这种情况是显然不行的,因为推一个点会使另一个点到圆内,那么规律是什么?

画图实验可以发现,当所有点都在三角形(或两角形)边的一侧时,推一下是不会产生矛盾的,如图

      

那么如何用简单的方法判断是否在同一侧呢?我用的方法是线段是否有交点。圆上的B类点两两连线,如果与图上的绿线相交,说明在两侧,不可以。这就是圆上只有B类的判断方法。

接下来是圆上A类B类都有。

我们担心的是这种情况


为了使B类在圆外,向右推,为了使A类在圆内,向左扩,这就矛盾了,通过上面的分析,我们很容易类比出判断方法:

所有A类点向B类点连线(指的是圆上的AB类点),如果没有与图上的绿线相交,说明在同侧,矛盾。


综上所述,梳理下步骤:

1、暴力A类的2个点加上B类的1个点,3点确定一个圈,判断

2、暴力A类的3个点,3点确定一个圈,判断

3、暴力A类的2个点,确定一个最小的圆,判断

4、判断方法:

    统计圆上的AB类点;

    B类点两两连线,与三角线的边判断有无交点;

    A类向B类连线,与三角线的边判断有无交点;


代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<map>
#include<queue>
#define eps 1e-6
using namespace std;
int dcmp(long double x) {if ( (fabs(x)<eps)) return 0;else return x<0?-1:1;}

struct Point
{
	long double x,y;
	Point(long double x=0,long double y=0):x(x),y(y){}
};

typedef Point Vector;

Vector operator +(Vector a,Vector b){return Vector(a.x+b.x,a.y+b.y);}
Vector operator -(Vector a,Vector b){return Vector(a.x-b.x,a.y-b.y);}
Vector operator *(Vector a,long double b){return Vector(a.x*b,a.y*b);}
Vector operator /(Vector a,long double b){return Vector(a.x/b,a.y/b);}
bool operator ==(Vector a,Vector b){ return dcmp(a.x==b.x)&& dcmp(a.y==b.y);}
long double Dot(Vector a,Vector b){return a.x*b.x+a.y*b.y;}
long double Length(Vector a){return sqrt(Dot(a,a));}
long double Cross(Vector a,Vector b){return a.x*b.y-a.y*b.x;}
//点在线段上(包含端点),在为 1 ,不在为 0
bool isPointOnSegment(Point P,Point A,Point B)
{
    return dcmp(Cross(A-P,B-P))==0 && dcmp(Dot(A-P,B-P))<=0;  // 不包含端点时为 <0
}

//线段相交判定,不包含端点,相交返回 1,不交返回 0,当包含端点是另加判断  isPointOnSegment
bool SPI(Point a1,Point a2,Point b1,Point b2)
{
    if (isPointOnSegment(a1,b1,b2)) return true;
    if (isPointOnSegment(a2,b1,b2)) return true;
    if (isPointOnSegment(b1,a1,a2)) return true;
    if (isPointOnSegment(b2,a1,a2)) return true;
    long double c1=Cross(a2-a1,b1-a1),c2=Cross(a2-a1,b2-a1),
           c3=Cross(b2-b1,a1-b1),c4=Cross(b2-b1,a2-b1);
    return dcmp(c1)*dcmp(c2)<0 && dcmp(c3)*dcmp(c4)<0;
}

Point waixin(Point a,Point b,Point c,long double &r)
{
	if (dcmp(Cross(b-a,c-a))==0)
	{
		long double c1=Length(a-b),c2=Length(a-c),c3=Length(b-c);
		long double d=max(c1,max(c2,c3));r=d/2;
		if(dcmp(d-c1)==0) return (a+b)/2;
		if(dcmp(d-c2)==0) return (a+c)/2;
		if(dcmp(d-c3)==0) return (c+b)/2;
	}
	long double a1=b.x-a.x,b1=b.y-a.y,c1=(a1*a1+b1*b1)/2;
	long double a2=c.x-a.x,b2=c.y-a.y,c2=(a2*a2+b2*b2)/2;
	long double d=a1*b2-a2*b1;
	return Point(a.x+(c1*b2-c2*b1)/d,a.y+(a1*c2-a2*c1)/d);
}

Point a[510],b[510],t[3];
char x[60000];int n,m;
bool check(Point v,long double r,int u)
{
    vector<Point> q,p;
    for (int i=1;i<=n;i++)
		if (dcmp(r-Length(a[i]-v))<0) return false;else
        if (dcmp(r-Length(a[i]-v))==0) q.push_back(a[i]);

	for (int i=1;i<=m;i++)
		if (dcmp(r-Length(b[i]-v))>0) return false;else
        if (dcmp(r-Length(b[i]-v))==0) p.push_back(b[i]);

    int pp=p.size(),qq=q.size();
    if (pp>1)
    for (int i=0;i<pp;i++) for (int j=i+1;j<pp;j++)
        for (int k=0;k<u;k++)
            if (SPI(p[i],p[j],t[k],t[(k+1)%u]))
            return false;
    for (int i=0;i<pp;i++) for (int j=0;j<qq;j++)
    {
        int l=0;
        for (int k=0;k<u;k++) if (SPI(p[i],q[j],t[k],t[(k+1)%u])) l++;
        if (!l) return false;
    }
	return true;
}

void abc()
{
    long double out=1e10;
	for (int i=1;i<=n;i++) for (int j=i+1;j<=n;j++)
    {
        a[n+m+1]=(a[i]+a[j])/2;
        for (int k=j+1;k<=n+m+1;k++)
        {
            long double r=0;int d=k>n?2:3;
            Point v=waixin(a[i],a[j],a[k],r);
            if (dcmp(r)==0) r=Length(v-a[i]);
            t[0]=a[i];t[1]=a[j];t[2]=a[k];
            if (check(v,r,d))out=min(out,r);
        }
    }
	if (out!=1e10)cout<<out<<endl;else puts("The Orcs are close");
}

void init()
{
    n=m=0;
    int l=strlen(x);l-=2; x[l+1]='\n';
    while(x[l]!='s')
    {
        if (x[l]=='n') break;
        while (x[l]!=',') l--;
        a[++n].y=atoi(x+l+1);x[l--]='\n';
        while (x[l]!='(') l--;
        a[n].x=atoi(x+l+1);l-=3;x[l+1]='\n';
    }
    gets(x);l=strlen(x);l-=2;
    while(x[l]!='s')
    {
        if (x[l]=='n') break;
        while (x[l]!=',') l--;
        b[++m].y=atoi(x+l+1);x[l--]='\n';
        while (x[l]!='(') l--;
        b[m].x=atoi(x+l+1);l-=3;x[l+1]='\n'; a[n+m]=b[m];
    }
}
int main()
{
    cout.precision(15);
    while (gets(x))
    {
        if (!(x[0]=='C' || x[0]=='O')) break;
    	init();
		if (n==1 || n==0)puts("0");else abc();
    }
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值