把一個平面上給出的點都包含進去的最小凸多邊形。逆時針輸出凸包的各個頂點。html
1.Graham掃描法 (O(n*logn))-------旋轉掃除的技術:node
2.Jarvis march步進法(O(n*h))h爲凸包的頂點數--------打包的技術ios
應用:求二維平面最遠點對。算法
uva,109ide
1 #include <iostream> 2 #include <vector> 3 #include <algorithm> 4 5 using namespace std; 6 7 struct node 8 { 9 double x,y; 10 //便於求出初始點 11 bool operator<(const node& a)const{ 12 return x<a.x || (x==a.x && y<a.y); 13 } 14 }; 15 16 17 typedef vector<node> Vnode;//凸包 18 typedef vector<Vnode> VVnode;//凸包個數 19 20 //叉積判斷是否向左轉。 21 double Isleft(node& p0,node& p1,node& p2) 22 { 23 return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y); 24 } 25 26 //求凸包 27 int Convex_hull(Vnode p,Vnode &h){ 28 int n=p.size(); 29 int k=0; 30 //按x升序而後y升序排列 31 sort(p.begin(),p.end()); 32 33 for(int i=0;i<n;i++){ 34 //上鍊 35 while(k>=2 && Isleft(h[k-2],h[k-1],p[i])<=0) 36 k--; 37 h[k++]=p[i]; 38 } 39 //下鏈 40 for(int i=n-2,t=k+1;i>=0;i--){ 41 while(k>=t && Isleft(h[k-2],h[k-1],p[i])<=0) 42 k--; 43 h[k++]=p[i]; 44 } 45 return k; 46 } 47 //檢查是否在凸多邊形內 48 int check(Vnode h, node p) { 49 int n = h.size(); 50 int i, j, c = 0; 51 for (i = 0, j = n-1; i < n; j = i++) 52 if ((((h[i].y <= p.y) && (p.y < h[j].y)) || ((h[j].y <= p.y) && (p.y < h[i].y))) && (p.x < (h[j].x - h[i].x) * (p.y - h[i].y) / (h[j].y - h[i].y) + h[i].x)) 53 c = !c; 54 return c; 55 } 56 //根據題意求凸包面積 57 double Area(Vnode p){ 58 int n=p.size(); 59 double s=0; 60 61 for(int i=1;i<n;i++){ 62 s+=((p[i-1].x*p[i].y-p[i].x*p[i-1].y))/2; 63 } 64 return s; 65 } 66 67 68 int main() 69 { 70 int n; 71 VVnode hull; 72 73 while(cin>>n && n!=-1) 74 { 75 Vnode p(n); 76 for(int i=0;i<n;i++) 77 cin>>p[i].x>>p[i].y; 78 79 Vnode h(n+1); 80 n=Convex_hull(p,h); 81 h.resize(n); 82 hull.push_back(h); 83 } 84 85 node k; 86 double a=0; 87 while(cin>>k.x>>k.y){ 88 VVnode::iterator it; 89 for(it=hull.begin();it<hull.end();it++) 90 { 91 if(check(*it,k)) 92 { 93 a+=Area(*it); 94 hull.erase(it); 95 break; 96 } 97 } 98 } 99 //輸出時帶兩位小數 100 cout.precision(2); 101 //fixed固定格式,floatfield表明以浮點數輸出 102 cout.setf(ios::fixed,ios::floatfield); 103 cout<<a<<endl; 104 105 return 0; 106 }
uva,10002函數
對於給定點對,求出凸包而後求其重心。spa
重心=(每一個三角形重心*有向面積)/總面積/3;code
通常三角形以源點(0,0)爲起點比較方便。注意三角形重心 ((x1+x2+x3)/3, (y1+y2+y3)/3)htm
因此求三角形重心用矢量加法/3則得重心。面積用叉積求/2.blog
1 #include <iostream> 2 #include <cstdio> 3 #include <cmath> 4 #include <algorithm> 5 6 using namespace std; 7 const int maxn=105; 8 const double eps=1e-10; 9 10 struct node 11 { 12 double x,y; 13 node(){} 14 node(double x,double y):x(x),y(y){} 15 16 bool operator<(const node& p)const{ 17 return x<p.x || (x==p.x && y<p.y); 18 } 19 //定義函數簡單方便 20 node operator+(node p){ 21 return node(x+p.x,y+p.y); 22 } 23 24 node operator-(node p){ 25 return node(x-p.x,y-p.y); 26 } 27 28 node operator*(double d){ 29 return node(x*d,y*d); 30 } 31 32 node operator/(double d){ 33 return node(x/d,y/d); 34 } 35 36 double det(node p){ 37 return x*p.y-y*p.x; 38 } 39 }ans[maxn],a[maxn]; 40 41 42 int n,len; 43 44 void Convex_hull() 45 { 46 sort(a,a+n); 47 len=0; 48 int i; 49 for(i=0;i<n;i++) 50 { 51 while(len>1 && (ans[len-1]-ans[len-2]).det(a[i]-ans[len-1])<=eps) len--; 52 ans[len++]=a[i]; 53 } 54 55 int tmp=len; 56 for(i=n-2;i>=0;--i){ 57 while(len>tmp && (ans[len-1]-ans[len-2]).det(a[i]-ans[len-1])<=eps) len--; 58 ans[len++]=a[i]; 59 } 60 --len; 61 } 62 //求多邊形面積 63 double Area() 64 { 65 double sum=0.0; 66 67 for(int i=0;i<len;i++) 68 sum+=ans[i].det(ans[i+1]); 69 return sum/2.0; 70 } 71 //求重心 72 node masscenter() 73 { 74 node res=node(0,0); 75 double s=Area(); 76 if(s<eps) return res; 77 78 for(int i=0;i<len;i++) 79 res=res+(ans[i]+ans[i+1])*(ans[i].det(ans[i+1])); 80 return res/s/6.0; 81 } 82 83 int main() 84 { 85 int i; 86 node res; 87 while(scanf("%d",&n) && n>=3){ 88 for(i=0;i<n;i++) scanf("%lf%lf",&a[i].x,&a[i].y); 89 90 Convex_hull(); 91 res=masscenter(); 92 printf("%.3lf %.3lf\n",res.x,res.y); 93 } 94 return 0; 95 }
10078
一開始是想的求點陣的凸包而後比較前後的點數,若是點減小則說明存在凹多邊形因此就yes了。
其實考慮欠周到,還要考慮點是否在凸包裏面= =,修正:由於可能他原來就是個凸的,可是有幾點共線了。
p1Xp2爲正數說明,p1在p2的順時針方向。不然在逆時針方向。二分查找到順時針方向的最近點,而後判斷是否在線段的左側就能夠了。附帶詳解:
1 #include <iostream> 2 #include <cstdio> 3 #include <cmath> 4 #include <algorithm> 5 6 using namespace std; 7 const int maxn=55; 8 const double eps=1e-10; 9 10 struct node 11 { 12 double x,y; 13 node(){} 14 node(double x,double y):x(x),y(y){} 15 16 bool operator<(const node& p)const{ 17 return x<p.x || (x==p.x && y<p.y); 18 } 19 20 node operator+(node p){ 21 return node(x+p.x,y+p.y); 22 } 23 24 node operator-(node p){ 25 return node(x-p.x,y-p.y); 26 } 27 28 node operator*(double d){ 29 return node(x*d,y*d); 30 } 31 32 node operator/(double d){ 33 return node(x/d,y/d); 34 } 35 36 double det(node p){ 37 return x*p.y-y*p.x; 38 } 39 }ans[maxn],a[maxn]; 40 41 42 int n; 43 44 int Convex_hull() 45 { 46 if(n<3) return n; 47 sort(a,a+n); 48 int len=0; 49 int i; 50 for(i=0;i<n;i++) 51 { 52 while(len>1 && (ans[len-1]-ans[len-2]).det(a[i]-ans[len-1])<=eps) len--; 53 ans[len++]=a[i]; 54 } 55 56 int tmp=len; 57 for(i=n-2;i>=0;--i){ 58 while(len>tmp && (ans[len-1]-ans[len-2]).det(a[i]-ans[len-1])<=eps) len--; 59 ans[len++]=a[i]; 60 } 61 return --len; 62 } 63 64 double cross(node p0, node p1, node p2) 65 { 66 return (p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y); 67 } 68 //二分算法判斷是否在凸多邊形內。 69 bool Compl_inside_convex(const node & p,node *con,int n) 70 { 71 if(n<3) return false; 72 if(cross(con[0],p,con[1])>-eps) return false; 73 if(cross(con[0],p,con[n-1])<eps) return false; 74 75 int i=2,j=n-1; 76 int line=-1; 77 78 while(i<=j) 79 { 80 int mid=(i+j)>>1; 81 if(cross(con[0],p,con[mid])>-eps) 82 { 83 line=mid; 84 j=mid-1; 85 } 86 else i=mid+1; 87 } 88 return cross(con[line-1],p,con[line])<-eps; 89 } 90 91 int main() 92 { 93 int i; 94 node res; 95 while(scanf("%d",&n),n){ 96 for(i=0;i<n;i++) scanf("%lf%lf",&a[i].x,&a[i].y); 97 98 int count=Convex_hull(); 99 int flag=0; 100 for(int i=0;i<n;i++) 101 //若是在凸多邊形內則原多邊形爲凹多邊形。 102 if(count>2 && Compl_inside_convex(a[i],ans,count)) 103 { 104 flag=1;break; 105 } 106 if(flag) printf("Yes\n"); 107 else printf("No\n"); 108 } 109 return 0; 110 }
1 double cross(cpoint p0, cpoint p1, cpoint p2) 2 { 3 return (p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y); 4 } 5 6 bool Compl_inside_convex(const cpoint & p,cpoint *con,int n) 7 { 8 if(n<3) return false; 9 if(cross(con[0],p,con[1])>-eps) return false; 10 if(cross(con[0],p,con[n-1])<eps) return false; 11 12 int i=2,j=n-1; 13 int line=-1; 14 15 while(i<=j) 16 { 17 int mid=(i+j)>>1; 18 if(cross(con[0],p,con[mid])>-eps) 19 { 20 line=mid; 21 j=mid-1; 22 } 23 else i=mid+1; 24 } 25 return cross(con[line-1],p,con[line])<-eps; 26 }
uva,681
注意精度問題,當二者相減的時候考慮極小的精度差,而後就是輸入輸出。。。見了你的鬼了。。
我一開始就光顧着把核心東西寫出來了。。後面提交了一次才發現仍是前面一道題目的條件。而後就wa了一下午。
1 #include <iostream> 2 #include <algorithm> 3 #include <cmath> 4 #include <cstdio> 5 #include <vector> 6 #include <cstdlib> 7 #include <cstring> 8 9 using namespace std; 10 #define eps 1e-10 11 12 double add(double a,double b) 13 { 14 if(abs(a+b)<eps*(abs(a)+abs(b))) return 0; 15 return a+b; 16 } 17 18 struct node 19 { 20 double x,y; 21 22 node operator-(node p){ 23 return node(add(x,-p.x),add(y,-p.y)); 24 } 25 26 double det(node p){ 27 return add(x*p.y,-y*p.x); 28 } 29 30 node(){} 31 node(double x,double y):x(x),y(y){} 32 }; 33 34 bool cmp(const node& a,const node& b) 35 { 36 if(fabs(a.y-b.y)>eps) 37 return a.y<b.y; 38 return a.x<b.x; 39 } 40 41 vector<node> convex_hull(vector<node> ps,int n) 42 { 43 sort(ps.begin(),ps.end(),cmp); 44 45 int k=0; 46 vector<node> qs(n*2); 47 48 for(int i=0;i<n;i++){ 49 while(k>1 && (qs[k-1]-qs[k-2]).det(ps[i]-qs[k-2])<=0) k--; 50 qs[k++]=ps[i]; 51 } 52 53 for(int i=n-2,t=k;i>=0;i--){ 54 while(k>t && (qs[k-1]-qs[k-2]).det(ps[i]-qs[k-2])<=0) k--; 55 qs[k++]=ps[i]; 56 } 57 qs.resize(k); 58 return qs; 59 } 60 61 int main() 62 { 63 int tc; 64 int n; 65 66 int x,y; 67 vector<node> p; 68 scanf("%d",&tc); 69 printf("%d\n",tc); 70 while(tc--) 71 { 72 p.clear(); 73 scanf("%d",&n); 74 for(int i=0;i<n;i++) 75 { 76 scanf("%d %d",&x,&y); 77 p.push_back(node(x,y)); 78 } 79 80 if(tc) scanf("%d",&x); 81 82 p=convex_hull(p,n); 83 84 printf("%d\n",(int)p.size()); 85 86 for(int i=0;i<(int)p.size();i++) 87 printf("%.0lf %.0lf\n",p[i].x,p[i].y); 88 89 if(tc) 90 printf("-1\n"); 91 92 } 93 return 0; 94 }