10445 - Make Polygon
http://uva.onlinejudge.org/external/104/10445.html
問題概要
ミスターピカソが描いた多角形で、内角の大きさで最小のものと最大のものを求めよう。
コード
#include<iostream> #include<vector> #include<cmath> #include<complex> #include<algorithm> using namespace std; typedef long double elem; typedef complex<elem> point,vec; const elem eps = 1.0e-10; const elem pi = acos(-1.0); inline elem deg(elem rad){ return (rad/pi)*180; } bool eq(elem a, elem b){ return abs(b-a)<eps; } bool lessthan(elem a, elem b){ return !eq(a,b) && a<b; } elem dot(vec a, vec b){ return a.real()*b.real()+a.imag()*b.imag(); } elem cross(vec a, vec b){ return a.real()*b.imag() - a.imag()*b.real(); } elem len(vec v){ return abs(v); } elem Radians(vec a, vec b){ return acos(dot(a,b)/(len(a)*len(b))); } bool isRight(vec base, vec isv){ if(eq(cross(base,isv),0)) return len(isv)<len(base); else return lessthan(cross(base,isv),0); } bool isLeft(vec base, vec isv){ if(eq(cross(base,isv),0)) return len(isv)<len(base); else return lessthan(0,cross(base,isv)); } struct Point{ int id; point p; Point():p(0,0){} Point( point p ):p(p){} bool operator<(const Point &t)const{ if( p.imag() < t.p.imag() ) return true; else if( eq( p.imag(), t.p.imag() ) ){ return p.real() < t.p.real(); } return false; } }; int main(){ while(true){ int n; elem min_rad = 2 * pi, max_rad = 0; bool brevclk = true; cin >> n; if( n < 3 )break; vector< Point > vp, tmpvp; for(int i = 0; i < n; ++i){ elem x, y; cin >> x >> y; Point p(point(x,y)); p.id = i; vp.push_back( p ); } Point topmost; topmost = vp[0]; for(int i = 0; i < n; ++i){ if( topmost < vp[i] ){ topmost = vp[i]; } } //cout << topmost.p << endl; if( isLeft( vec( topmost.p - vp[(topmost.id-1+n)%n].p ), vec( vp[(topmost.id+1)%n].p - topmost.p ) ) ) brevclk = true; else brevclk = false; for(int i = 0; i < n; ++i){ point p = vp[(i+1)%n].p; point a = vp[i].p; point b = vp[(i+2)%n].p; vec pa = a - p; vec pb = b - p; elem rad = Radians(pa,pb); bool rev = brevclk ? isLeft(pa,pb) : isRight(pa,pb); if( rev ){ rad = 2*pi - rad; } max_rad = max( max_rad, rad ); min_rad = min( min_rad, rad ); } printf("%.6Lf %.6Lf\n", deg(min_rad), deg(max_rad) ); } return 0; } // nagamonmon
解法
まず点列が反時計回りか時計回りかを判断する(一番上の点とそれに隣接する点について、ふたつのベクトルをつくり左右判定)。その後内角の大きさを求めていく。