No.198ではまりまくった。
かかった時間は順に6分・30分・5分・10分と言った感じです。
今日はUnKoderといいハマってWA連発が多いなぁ。
http://yukicoder.me/problems/433
問題
2次元座標上で5つの点が与えられる。
五芒星を書けるか判定せよ。
解法
5つの点を辿る順番はnext_permutationで総当たりしてしまえばよい。
5個の点が以下の順に並んでいるとする。
i番と(i+1)%5番の頂点を結んだ直線を考えたとき、(i+2)%5番と(i+4)%5番の頂点が、(i+3)%5番の頂点と直線を跨いで反対側にあれば、それらは五芒星を成す。
以下の図で0-1を結んだ線に対し、2,3,4がどちらにあるかを考えると分かりやすい。
2頂点が直線を跨いでるかどうかは、2つの符号付き三角形の面積の積が負になるか判定すればよい。
このテクは以前yukicoderで使ったね。
別解としては、5点が凸包を成すか判定する方法がある。
0 / 3 / 2 / / 1 4
int X[5],Y[5]; int P[5]; template<class C> C veccross(pair<C,C> p1,pair<C,C> p2,pair<C,C> p3) { p3.first-=p1.first;p2.first-=p1.first; p3.second-=p1.second;p2.second-=p1.second; return p3.first*p2.second-p2.first*p3.second; } bool ok() { int i; pair<ll,ll> PP[5]; FOR(i,5) PP[i]=make_pair(X[P[i]],Y[P[i]]); FOR(i,5) { ll c1=veccross(PP[i],PP[(i+1)%5],PP[(i+2)%5]); ll c2=veccross(PP[i],PP[(i+1)%5],PP[(i+3)%5]); ll c3=veccross(PP[i],PP[(i+1)%5],PP[(i+4)%5]); if(c1*c2>=0 || c3*c2>=0) return false; } /* if(veccross(PP[i],PP[1],PP[2])*veccross(PP[0],PP[1],PP[3])>=0) return false; if(veccross(PP[0],PP[1],PP[2])*veccross(PP[0],PP[1],PP[3])>=0) return false; if(veccross(PP[0],PP[1],PP[4])*veccross(PP[0],PP[1],PP[3])>=0) return false; if(veccross(PP[1],PP[2],PP[0])*veccross(PP[1],PP[2],PP[4])>=0) return false; if(veccross(PP[1],PP[2],PP[3])*veccross(PP[1],PP[2],PP[4])>=0) return false; if(veccross(PP[2],PP[3],PP[0])*veccross(PP[2],PP[3],PP[1])>=0) return false; if(veccross(PP[2],PP[3],PP[0])*veccross(PP[2],PP[3],PP[4])>=0) return false; if(veccross(PP[3],PP[4],PP[1])*veccross(PP[3],PP[4],PP[0])>=0) return false; if(veccross(PP[3],PP[4],PP[1])*veccross(PP[3],PP[4],PP[2])>=0) return false; if(veccross(PP[4],PP[0],PP[2])*veccross(PP[4],PP[0],PP[1])>=0) return false; if(veccross(PP[4],PP[0],PP[2])*veccross(PP[4],PP[0],PP[3])>=0) return false; */ return true; } void solve() { int i,j,k,l,r,x,y; string s; FOR(i,5) { cin>>X[i]>>Y[i]; P[i]=i; } do { if(ok()) return _P("YES\n"); } while(next_permutation(P,P+5)); _P("NO\n"); }
まとめ
先にこっちやればよかった。