プロジェクトオイラー問292

https://projecteuler.net/problem=292
周長120までのピタゴラス多角形の種類数をこたえる問題。
数分の計算時間で答えが出るところまで到達したので満足。
多分エレガントな漸化式で解くのだろうけど、力技の漸化式でだましだまし解。
P(LIMIT)に設定しているのでコード中のLIMIT=30をLIMIT=120に変更すると答えを計算する。

#include<stdio.h>
#include<set>
#include<map>
#include<iostream>
int gcd ( int a, int b ){
 	int c;
 	while ( a != 0 ) {
 	   c = a; a = b%a;  b = c;
 	}
  	return b;
}

struct E{
	int dx,dy,len;
	bool operator<(const E& e1)const{
		if(dx!=e1.dx)return dx<e1.dx;
		return dy<e1.dy;
	}
};
 
struct E2{
	int x,y,len,dx,dy,sx,sy;
	bool operator<(const E2& e2)const{
		if(x!=e2.x)return x<e2.x;
		if(y!=e2.y)return y<e2.y;
		if(dx!=e2.dx)return dx<e2.dx;
		if(dy!=e2.dy)return dy<e2.dy;
		if(sx!=e2.sx)return sx<e2.sx;
		if(sy!=e2.sy)return sy<e2.sy;
		return len<e2.len; 
	}
};
 
bool ok(int x1,int y1,int x2,int y2){ 
	return x1*y2-x2*y1>0;
}
 
std::set<E> memo;
const int LIMIT=30;//とりあえずP(30)に設定ここを120に変えると数分の計算で問題の答えが出る
 
int main(){
 
	E e1;
	e1.len=1;
	e1.dx=-1;
	e1.dy=0;
	memo.insert(e1);
	e1.dx=1;
	e1.dy=0;
	memo.insert(e1);
	e1.dx=0;
	e1.dy=1;
	memo.insert(e1);
	e1.dx=0;
	e1.dy=-1;
	memo.insert(e1);
	for(int m=2;m*m+1<=LIMIT;m++){
		for(int n=1;n<m;n++){
 
			int c=m*m+n*n;
			if(c>LIMIT)break;
			if(gcd(m,n)!=1)continue;
			if((m-n)%2!=1)continue;
 
			e1.len=c;
 			e1.dx=m*m-n*n;
			e1.dy=2*m*n;
			memo.insert(e1);
			e1.dx=-e1.dx;
			memo.insert(e1);
			e1.dx=-e1.dx;
			e1.dy=-e1.dy;
			memo.insert(e1);
			e1.dx=n*n-m*m;
			e1.dy=-2*m*n;
			memo.insert(e1);
 
			e1.dy=m*m-n*n;
		e1.dx=2*m*n;
			memo.insert(e1);
			e1.dx=-e1.dx;
			memo.insert(e1);
			e1.dx=-e1.dx;
			e1.dy=-e1.dy;
			memo.insert(e1);
			e1.dy=n*n-m*m;
			e1.dx=-2*m*n;
			memo.insert(e1);
		}
	}
	printf("%d\n",memo.size());
	std::set<E>::iterator it;
	E2 e2;
	std::map<E2,long long int> ms;
	for(it=memo.begin();it!=memo.end();it++){
		e1=(*it);
		if(e1.dx>0&&e1.dy>=0){
 
			e2.dx=e1.dx;
			e2.dy=e1.dy;
			e2.sx=e1.dx;
			e2.sy=e1.dy;
			for(int i=1;i*e1.len<LIMIT/2;i++){
				e2.len=e1.len*i;
				e2.x=e1.dx*i;
				e2.y=e1.dy*i;
				ms[e2]++;
			}
		}
	}
	long long int ans=0;
	for(int j=2;j<=LIMIT;j++){
		std::map<E2,long long int> next;
		std::map<E2,long long int>::iterator mIt;
		long long int add=0;
		for(mIt=ms.begin();mIt!=ms.end();mIt++){
			e2=(*mIt).first;
			long long int c=(*mIt).second;
 			for(it=memo.begin();it!=memo.end();it++){
 
				e1=(*it);
 
				E2 e3; 
				for(int i=1;e2.len+i*e1.len<=LIMIT;i++){
					e3.x=e2.x+e1.dx*i;
					e3.y=e2.y+e1.dy*i;
					e3.len=e2.len+e1.len*i;
					e3.dx=e1.dx;
 					e3.dy=e1.dy;
					e3.sx=e2.sx;
					e3.sy=e2.sy;
					if(ok(e1.dx,e1.dy,e2.dx,e2.dy)==false)continue;
					if(e3.x==0&&e3.y==0){
 						add+=c;
					}else{
						if(ok(e3.x,e3.y,e2.x,e2.y)==false)continue;
						if(ok(e3.x,e3.y,e2.sx,e2.sy)==false)continue;
						int len2=e3.x*e3.x+e3.y*e3.y;
						int len3=(LIMIT-e3.len)*(LIMIT-e3.len);
 						if((len2>len3)||(len2>(LIMIT/2)*(LIMIT/2)))continue;
						next[e3]+=c;
					}
 				}
			}
		}
		std::cout<<add<<" "<<j<<" "<<ans<<" "<<next.size()<<"\n";
		add=add*4/j;
 		ans+=add;
		ms.clear();
		ms.insert(next.begin(),next.end());
 	}
	std::cout<<"\nans="<<ans<<"\n";
}
最終更新:2015年10月31日 10:46