题目来源:
http://poj.org/problem?id=3384
分析: 用半平面交将多边形的每条边一起向“内”推进R,得到新的多边形(半平面交),然后求多边形的最远两点。
代码如下:
const double EPS = 1e-10 ;
const int Max_N = 105 ; double add(double a, double b){ return (fabs(a + b) < EPS * (fabs(a) + fabs(b)) )? 0 : (a + b) ; } struct Point{ double x, y; Point(){} Point(double x, double y):x(x),y(y){} Point operator - (Point a){ return Point(add(x , -a.x) , add(y , -a.y)) ; } Point operator +(Point a){ return Point(add(x , a.x) ,add(y , a.y) ) ; } Point operator * (double d){ return Point(x * d , y * d) ; } double operator ^(Point a){ return add(x * a.y , -y * a.x) ; } double dist(Point a){ return sqrt(add((x - a.x)*(x - a.x) ,(y - a.y)*(y - a.y) )) ; } }; struct Line{ Point st, ed; Line(){} Line(Point s, Point e):st(s),ed(e){} bool onRight(Point a){ // 点在线右边 return ((ed - st)^(a - st)) < 0 ; } bool parallel(Line l){ return ((ed - st)^(l.ed - l.st)) == 0 ; } Point CrossNode(Line l){ double d1 = (l.ed - l.st)^(l.st - st) ; double d2 = (l.ed - l.st)^(ed - st) ; return st + (ed - st)*(d1 / d2) ; } double jijiao(){ return atan2(ed.y - st.y , ed.x - st.x) ; } }; bool operator < (Line l, Line r){ double lp= l.jijiao() ; double rp = r.jijiao() ; if(fabs(lp - rp) > EPS) return lp < rp ; return ((l.st - r.st)^(r.ed - r.st)) < 0 ; } Line dequeue[Max_N] ; Point pt[Max_N] ; int halfPanelCross(Line line[] , int ln) { int i, tn; sort(line , line + ln) ; for(i = tn = 1; i < ln ; i++) if(fabs(line[i].jijiao() - line[i - 1].jijiao()) > EPS) line[tn ++] = line[i] ; ln = tn ; int bot = 0 , top = 1 ; dequeue[0] = line[0] ; dequeue[1] = line[1] ; for(i = 2 ; i < ln ; i++){ if(dequeue[top].parallel(dequeue[top - 1]) || dequeue[bot].parallel(dequeue[bot + 1])) return 0 ; while(bot < top && line[i].onRight(dequeue[top].CrossNode(dequeue[top - 1]))) top -- ; while(bot < top && line[i].onRight(dequeue[bot].CrossNode(dequeue[bot + 1]))) bot ++ ; dequeue[++ top] = line[i] ; } while(bot < top && dequeue[top].onRight(dequeue[bot].CrossNode(dequeue[bot + 1]))) bot ++ ; while(bot < top && dequeue[bot].onRight(dequeue[top].CrossNode(dequeue[top - 1]))) top -- ; if(top <= bot + 1) return 0 ; int n = 0 ; for(i = bot ; i < top ; i++) pt[n ++] = dequeue[i].CrossNode(dequeue[i + 1]) ; if(bot < top + 1) pt[n ++] = dequeue[bot].CrossNode(dequeue[top]) ; return n ; } Line List[Max_N] , tmp[Max_N] ; // 多边形每条有向直线向内平移 h 距离 后的有向直线 利用的是三角形的相似 void PolygonChange(double h , int ln){ double len , dx ,dy ; for(int i = 0 ; i< ln ; i++){ len = List[i].ed.dist(List[i].st) ; dx = (List[i].st.y - List[i].ed.y) / len * h ; dy = (List[i].ed.x - List[i].st.x) / len * h ; tmp[i].st.x = List[i].st.x + dx ; tmp[i].st.y = List[i].st.y + dy ; tmp[i].ed.x = List[i].ed.x + dx ; tmp[i].ed.y = List[i].ed.y + dy ; } } int main(){ double r ; Point p[Max_N] ; int n; while(scanf("%d%lf" , &n , &r) != EOF) { for(int i = 0 ; i < n ; i++){// 题目中顶点是顺时针输入 scanf("%lf%lf" , &p[i].x , &p[i].y ) ; } for(int i = 0 ; i < n ; i++) List[i] = Line(p[(i+1) % n] , p[i] ) ; //构造有向直线(半平面在向量的左边) PolygonChange(r, n) ; int tn ; tn = halfPanelCross(tmp , n) ; double Max = 0 ; int f1 = 0 ,f2 = 0 ; for(int i = 0 ; i < tn ; i++){ //寻找凸多边形中最远点对 , 枚举 for(int j = i +1 ; j < tn ; j++){ if(pt[i].dist(pt[j]) > Max){ Max = pt[i].dist(pt[j]) ; f1 = i ; f2 = j ; } } } printf("%.4lf %.4lf %.4lf %.4lf " , pt[f1].x ,pt[f1].y , pt[f2].x , pt[f2].y) ; } }