题目链接 http://poj.org/problem?id=3384
题意:两个圆半径均为r(可重合但不能超出多边形边界)覆盖一个多边形,覆盖的面积最大时求两点坐标。
思路:若多边形足够大,则随便放,不重叠即可。若多边形较小,则需圆与多边形相切且尽量拉大圆心距。
方法是把所有边向内平移r(半径),然后半平面交,则两圆心在半平面交集的一对最远点上。
这个题貌似测试数据比较奇葩。。
#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
const double EPS=1e-11;
const int NUM=1510;
int DB (double x)
{
if (x>EPS)
return 1;
if (x<-EPS)
return -1;
return 0;
}
struct Point
{
double x,y;
Point(){}
Point(double _x,double _y)
{
x=_x;
y=_y;
}
void get ()
{
scanf("%lf%lf",&x,&y);
}
void Out ()
{
printf("%.4lf %.4lf",x,y);
}
}points[NUM],p[NUM],q[NUM];
int n,r;
int cCnt,curCnt;
void getline (Point x,Point y,double &a,double &b,double &c)
{
a = y.y - x.y;
b = x.x - y.x;
c = y.x * x.y - x.x * y.y;
}
Point intersect (Point x,Point y,double a,double b,double c) //相交
{
double u = fabs(a * x.x + b * x.y + c);
double v = fabs(a * y.x + b * y.y + c);
return Point( (x.x * v + y.x * u) / (u + v) , (x.y * v + y.y * u) / (u + v) );
}
/*半平面相交(直线切割多边形)(点标号从1开始)*/
void cut (double a,double b ,double c)
{
int i;
curCnt = 0;
for (i=1;i<=cCnt;i++)
{
if (DB(a*p[i].x + b*p[i].y + c) >= 0)
q[++curCnt] = p[i];
else
{
if (DB(a*p[i-1].x + b*p[i-1].y + c) > 0)
q[++curCnt] = intersect(p[i],p[i-1],a,b,c);
if (DB(a*p[i+1].x + b*p[i+1].y + c) > 0)
q[++curCnt] = intersect(p[i],p[i+1],a,b,c);
}
}
for (i=1;i<=curCnt;i++)
p[i] = q[i];
p[curCnt+1] = q[1];
p[0] = p[curCnt];
cCnt = curCnt;
}
void GuiZhengHua ()
{
//规整化方向,逆时针变顺时针,顺时针变逆时针
for (int i=1;i<(n+1)/2;i++)
swap(points[i], points[n-i]);
}
void initial ()
{
for (int i=1;i<=n;i++)
p[i] = points[i];
p[n+1] = p[1];
p[0] = p[n];
cCnt = n;
}
double dis (Point a,Point b)
{
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
void Deal ()
{
int i,j;
//注意:默认点是顺时针,如果题目不是顺时针,规整化方向
initial ();
for (i=1;i<=n;i++)
{
Point ta, tb, tt;
tt.x = points[i+1].y - points[i].y;
tt.y = points[i].x - points[i+1].x;
double k = r / sqrt(tt.x * tt.x + tt.y * tt.y);
tt.x = tt.x * k;
tt.y = tt.y * k;
ta.x = points[i].x + tt.x;
ta.y = points[i].y + tt.y;
tb.x = points[i+1].x + tt.x;
tb.y = points[i+1].y + tt.y;
double a,b,c;
getline(ta,tb,a,b,c);
cut(a,b,c);
}
Point ansa,ansb;
double dmax=-1;
for (i=1;i<=cCnt;i++)
for (j=1;j<=cCnt;j++) //不能写成j=i+1,因为可能存在平移后退化成点
if (dis(p[i],p[j])>dmax)
{
dmax=dis(p[i],p[j]);
ansa=p[i];
ansb=p[j];
}
printf("%.4lf %.4lf %.4lf %.4lf\n",ansa.x,ansa.y,ansb.x,ansb.y);
}
int main ()
{
while (~scanf("%d%d",&n,&r))
{
for (int i=1;i<=n;i++)
points[i].get();
points[0]=points[n];
points[n+1] = points[1];
Deal ();
}
return 0;
}
/*
Input
4 1
0 0
0 2
2 2
2 0
Output
1.0000 1.0000 1.0000 1.0000
4 1
1 1
1 -1
-1 -1
-1 1
0.0000 0.0000 0.0000 0.0000
*/