kmjp's blog

競技プログラミング参加記です

yukicoder : No.199 星を描こう

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");
	
}

まとめ

先にこっちやればよかった。