#include #include #include #include #include #include /* ACMプログラミング・コンテスト 2010年 国内予選 Problem C ポロック予想 この問題は、ある1つの数字が、ある数字列の足し算で表わされるときに、 その足し算を構成する数が最小の組み合わせを見つけ出す問題である。数字列には 必ず1が入るため、答えが存在しないことはあり得ない。 解法例:基本的な考え方は、ある数字が正四面体数でない場合、正四面体数で引いた数字を 再度確認する、という方法である。そして、足し算を構成する数字が少ない方がよいため、 横型探索のように、まずは、1つの正四面体数で足し算を構成できるかを確認し、次に、 2つの正四面体で足し算を構成できないかを確認する。2つの正四面体数とは、最初に 1つの正四面体数で構成できなかった数を、正四面体数で引いた数が、正四面体数で あるかどうかをチェックすることで実現される。これを再帰的に繰り返すことによって、 横型探索のように、探索していく。調査しなければいけない数は、最大で、1*10^6 - 180 となるため、この大きさの配列が必要になる。但し、同じ数字は2回チェックする必要は ないため、サイズの小さいcharで作成し、添え字の数字がチェックする数字で、その 添え字の表わす配列に0:未チェック、1:これからチェックする、2:すでにチェック済み の値をそれぞれ入れることにする。 また、以下のプログラムは、次の点で効率的ではない。新しくチェックしなければいけない 数字が見つかった時に、それが例え正四面体数であったとしてもそれはチェックせずに、 とりあえずバッファに保存してしまう。そして、今現在チェックしなければいけない数字が 全て終わった後で、またチェックしなければいけない数字を全て出してまた、次のチェックを 開始することになる。そこで、正四面体数を見つけて、探索が終了することになる。 この部分を修正しなくてもとりあえず動いたので、ソースの簡略さを優先して、直していない。 */ // 正四面体数を保存する配列の大きさ // 1*10^6以下の正四面体数は180個ある。 #define SIZE_NUMS 180 // 調査するための数字を記録するバッファサイズ // 問題より1*10^6のサイズとする。 #define SIZE_REMS 1000000 // 数字(v)がnum配列にあるかどうかを確認する。 // sizeは、配列numsのサイズ。typeは0の場合は // 配列にある数字の全てを検索対象とする。1の場合 // には奇数の数字のみを検索対象とする。 int find(int v,int nums[],int size,int type) { for(int cnt=0;nums[cnt]!=-1 && cntnums[ncnt] && ncnt