atcoderD三角形の分類

2 次元平面上の N 個の点が与えられます。 i 番目の点の座標は (xi,yi) です。ただし、このうちのどの 3 点も同一直線上にありません。

N 点のうち 3 点を選ぶことによってこの 3 点を頂点とした三角形を作ることを考えます。三角形は全部で N*(N−1)*(N−2)⁄6 個できます。 これらの三角形のうち、鋭角三角形の個数、直角三角形の個数、鈍角三角形の個数を求めてください。

ただし、鋭角三角形とは、3 つの角が全て 90° より小さい三角形で、直角三角形とは、ある 1 つの角が 90° である三角形で、 鈍角三角形とは、ある 1 つの角が 90° より大きい三角形のことをいいます。

N<=2000


2点を適当に選び一点を原点O、一点をA0とする。
その2点からみて半時計回りに点を整列しA0~An-2とする。
後は、A0からみて鈍角になるAiOA0~AjOA0の範囲を求める。
A1OAiが鈍角になるAiの範囲はAIOA0を少し回せばいいので尺取虫法で解けると分かる。
OAkAiを少し回すとOAk+1Aiが鈍角になる範囲はすぐにわかる。
一周くるりと回せばよい。

後はこれを全ての点をOにして繰り返す。
Prolog的発想。

自力解法で30/260位。
1位は圧倒的だな。
私は4流アマチュアプログラマとして最底辺を徘徊するだけです。


#include<stdio.h>
#include<math.h>
#include<vector>
#include<algorithm>
#include<iostream>
#include<string.h>
 
double calcCosA(double x1,double y1,double x2,double y2,double x3,double y3){
double dx2=x2-x1;
double dy2=y2-y1;
double dx3=x3-x1;
double dy3=y3-y1;
return (dx2*dx3+dy2*dy3)/(hypot(dx2,dy2)*hypot(dx3,dy3));
}
double calcSinA(double x1,double y1,double x2,double y2,double x3,double y3){
double dx2=x2-x1;
double dy2=y2-y1;
double dx3=x3-x1;
double dy3=y3-y1;
return (dx2*dy3-dy2*dx3)/(hypot(dx2,dy2)*hypot(dx3,dy3));
}
 
int naiseki(int x0,int y0,int x1,int y1,int x2,int y2){
int dx1=x1-x0;
int dy1=y1-y0;
int dx2=x2-x0;
int dy2=y2-y0;
return dx1*dx2+dy1*dy2;
}
int gaiseki(int x0,int y0,int x1,int y1,int x2,int y2){
int dx1=x1-x0;
int dy1=y1-y0;
int dx2=x2-x0;
int dy2=y2-y0;
return dx1*dy2-dx2*dy1;
}
struct E{
int x,y;
double cosA,sinA;
bool operator<(const E& e)const{
	if((sinA>=0)&&(e.sinA>=0)){
		return cosA>e.cosA;
	}else if((sinA>=0)&&(e.sinA<0)){
		return true;
	}else if((sinA<0)&&(e.sinA>=0)){
		return false;
	}else{
		return cosA<e.cosA;
	}
}
};
 
int main(){
int n;
int xs[2001],ys[2001];
scanf("%d",&n);
long long int ans0=0,ans1=0,ans2=0,n1=n;
for(int i=0;i<n;i++){
	scanf("%d %d",&xs[i],&ys[i]);
}

int c=0;
for(int i=0;i<n;i++){
	E e1;
	int k=(i+1)%n;
	std::vector<E> vec;
	for(int j=0;j<n;j++){
		if(j==i)continue;
		e1.x=xs[j];
		e1.y=ys[j];
		e1.cosA=calcCosA(xs[i],ys[i],xs[k],ys[k],xs[j],ys[j]);
		e1.sinA=calcSinA(xs[i],ys[i],xs[k],ys[k],xs[j],ys[j]);
		vec.push_back(e1);
	}
	std::sort(vec.begin(),vec.end());
	int x0=xs[i];
	int y0=ys[i];
	int p1=1;
	int p2=1;
	int pp1=(vec.size()-1);
	int pp2=pp1;
	for(int j=0;j<vec.size();j++)
	{
		//反時計回り
		int x1=vec[j].x;
		int y1=vec[j].y;
		//printf("(%d %d)",x1-x0,y1-y0);

		if(j==p1){
			p1=(p1+1)%vec.size();
		}
		bool bad=false;
		int type=0;
		while(1){
			int x2=vec[p1].x;
			int y2=vec[p1].y;
			int d=naiseki(x0,y0,x1,y1,x2,y2);
			int g=gaiseki(x0,y0,x1,y1,x2,y2);
			if((d==0)&&(g>0)){				
				ans1++;
				break;
			}
			if((d<=0)&&(g>0)){
				break;
			}
			if(g<0){
				bad=true;
				break;
			}
			p1=(p1+1)%vec.size();
			if(p1==j){
				bad=true;
				break;
			}
		}
		if(p1!=j){
			bool bad2=false;
			while(1){
				int x2=vec[p2].x;
				int y2=vec[p2].y;
				int g=gaiseki(x0,y0,x1,y1,x2,y2);
				if(g<0)break;
				p2=(p2+1)%vec.size();
				if(p2==j){
					break;
				}
			}	
			if(bad==false&&bad2==false){
				if(p1<p2){
					ans2+=p2-p1;
				}else if(p1>p2){
					ans2+=(vec.size()-p1+p2);
				}
				//printf("%d\n",ans2);
			}
		}
	}
}

std::cout<<n1*(n1-1)*(n1-2)/6-ans2<<" "<<ans1<<" "<<ans2-ans1<<"\n";
}
最終更新:2016年10月08日 17:10