poj 3608 旋转卡壳求不相交凸包最近距离;
生活随笔
收集整理的這篇文章主要介紹了
poj 3608 旋转卡壳求不相交凸包最近距离;
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題目鏈接:http://poj.org/problem?id=3608
#include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<algorithm> #include<queue> using namespace std; const int maxn = 10500; const int maxe = 100000; const int INF = 0x3f3f3f; const double eps = 1e-8; const double PI = acos(-1.0);struct Point{double x,y;Point(double x=0, 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 , double p){return Vector(A.x*p,A.y*p);} Vector operator / (Vector A , double p){return Vector(A.x/p,A.y/p);}bool operator < (const Point& a,const Point& b){return a.x < b.x ||( a.x == b.x && a.y < b.y); }int dcmp(double x){if(fabs(x) < eps) return 0;else return x < 0 ? -1 : 1; } bool operator == (const Point& a, const Point& b){return dcmp(a.x - b.x) == 0 && dcmp(a.y - b.y) == 0; }///向量(x,y)的極角用atan2(y,x); double Dot(Vector A, Vector B){ return A.x*B.x + A.y*B.y; } double Length(Vector A) { return sqrt(Dot(A,A)); } double Angle(Vector A, Vector B) { return acos(Dot(A,B) / Length(A) / Length(B)); } double Cross(Vector A, Vector B) { return A.x*B.y - A.y * B.x; }Vector Rotate(Vector A, double rad) { return Vector(A.x*cos(rad)-A.y*sin(rad),A.x*sin(rad)+A.y*cos(rad)); }///求點P到線段AB的距離,先看Q點在線段外還是內;利用點積就可以, double DistanceToSegment(Point P,Point A,Point B){if(A == B) return Length(P-A);Vector v1 = B - A,v2 = P - A,v3 = P - B;if(dcmp(Dot(v1,v2)) < 0) return Length(v2);else if(dcmp(Dot(v1,v3) > 0)) return Length(v3);else return fabs(Cross(v1,v2))/Length(v1); } ///求線段AB與線段CD的距離; double DistanceBetweenSegment(Point A,Point B,Point C,Point D){return min(min(DistanceToSegment(A,C,D),DistanceToSegment(B,C,D)),min(DistanceToSegment(C,A,B),DistanceToSegment(D,A,B))); }//凸包: /**Andrew算法思路:首先按照先x后y從小到大排序(這個地方沒有采用極角逆序排序,所以要進行兩次掃描),刪除重復的點后得到的序列p1,p2.....,然后把p1和p2放到凸包中。從p3開始,當新的 點在凸包“前進”方向的左邊時繼續,否則依次刪除最近加入凸包的點,直到新點在左邊;**///Goal[]數組模擬棧的使用; int ConvexHull(Point* P,int n,Point* Goal){sort(P,P+n);int m = unique(P,P+n) - P; //對點進行去重;int cnt = 0;for(int i=0;i<m;i++){ //求下凸包;while(cnt>1 && dcmp(Cross(Goal[cnt-1]-Goal[cnt-2],P[i]-Goal[cnt-2])) <= 0) cnt--;Goal[cnt++] = P[i];}int temp = cnt;for(int i=m-2;i>=0;i--){ //逆序求上凸包;while(cnt>temp && dcmp(Cross(Goal[cnt-1]-Goal[cnt-2],P[i]-Goal[cnt-2])) <= 0) cnt--;Goal[cnt++] = P[i];}if(cnt > 1) cnt--; //減一為了去掉首尾重復的;return cnt; }double solve(Point* P1,Point* Q1,int Minid,int Maxid,int N,int M){double temp,ret = 1e5;P1[N] = P1[0]; Q1[M] = Q1[0];for(int i=0;i<N;i++){while(temp = dcmp(Cross(Q1[Maxid]-Q1[Maxid+1],P1[Minid+1]-P1[Minid]))> 0) //這一步最難理解:要理解怎樣才能使Q1[Maxid]Q1[Maxid+1]這條線段最接近線段P1[Minid+1]P1[Minid];Maxid = (Maxid+1)%M; // 先以P1[Minid]為定點,旋轉Q1[Maxid];if(temp < 0) ret = min(ret,DistanceToSegment(Q1[Maxid],P1[Minid],P1[Minid+1]));else ret = min(ret,DistanceBetweenSegment(P1[Minid],P1[Minid+1],Q1[Maxid],Q1[Maxid+1]));\Minid = (Minid + 1)%N; //再旋轉P1[Minid]; }return ret; } Point read_point(){Point A;scanf("%lf %lf",&A.x,&A.y);return A; }/*******************************分割線******************************/ Point P[maxn],Q[maxn]; Point P1[maxn],Q1[maxn]; //利用凸包算法使坐標逆時針化后的存儲; int N,M; int Maxid,Minid;void GetMaxandMin(int& Maxid,int& Minid){Maxid = 0; Minid = 0;for(int i=1;i<N;i++){if(P1[i].y < P1[Minid].y) Minid = i;}for(int i=1;i<M;i++){if(Q1[i].y > Q1[Maxid].y) Maxid = i;} }int main() {//freopen("E:\\acm\\input.txt","r",stdin);while(cin>>N>>M && N+M){for(int i=0;i<N;i++) P[i] = read_point();N = ConvexHull(P,N,P1);for(int i=0;i<M;i++) Q[i] = read_point();M = ConvexHull(Q,M,Q1);GetMaxandMin(Maxid,Minid);double ans = solve(P1,Q1,Minid,Maxid,N,M);printf("%.5f\n",ans);} } View Code?
轉載于:https://www.cnblogs.com/acmdeweilai/p/3258673.html
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的poj 3608 旋转卡壳求不相交凸包最近距离;的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: poj 1987 树的分治
- 下一篇: 推荐家长与师生阅读3078:极度聪明的孩