トップページに戻る
次のC#のサンプルへ
前のC#のサンプルへ
Cマガ電脳クラブ(第035回) 2
問題
2を、分子が1の分数 (以下単位分数と呼ぶ) の和で表すことを考える。分母が同じものは2個以上使えないとすると、
12個以上の単位分数が必要になる。 12個の和で表した例をひとつあげる。
1 1 1 1 1 1 1 1 1 1 1 1
2 = - + - + - + - + - + - + - + -- + -- + -- + -- + --
2 3 4 5 6 8 9 10 12 15 20 72
このように「2を、分母の異なる12個の単位分数の和で表す」例はこのほかにもたくさんある。
そこで、12個の単位分数の分母のうちで一番大きなもの (例では72) に注目する。
この"最大の分母"がなるべく小さくなる例を探してほしい。
答えは例と同じように式の形でお願いする。
ただし、分母になれるのは2以上の整数で、負の数は認めない。
ソース
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
var sw = System.Diagnostics.Stopwatch.StartNew();
for (int MaxBunbo = 2 + 12 - 1; MaxBunbo < int.MaxValue; MaxBunbo++) {
Console.WriteLine("分母の最大値={0,2}で解を調査中。経過時間={1}",
MaxBunbo, sw.Elapsed);
List<int[]> BunboArrList = DeriveBunboArrList(MaxBunbo);
if (BunboArrList.Count > 0) {
Console.WriteLine("分母の最大値={0,2}で解を発見。経過時間={1}",
MaxBunbo, sw.Elapsed);
foreach (int[] AnyArr in BunboArrList) {
Array.Sort(AnyArr);
for (int I = 0; I <= AnyArr.GetUpperBound(0); I++) {
Console.Write("1/{0}", AnyArr[I]);
Console.Write(I != AnyArr.GetUpperBound(0) ? " + " : " = 2");
}
Console.WriteLine();
}
return;
}
}
}
struct JyoutaiDef
{
internal int CurrVal;
internal List<int> BunboList;
}
//分母の最大値を引数として、単位分数の和が2になる分母の組み合わせを返す
static List<int[]> DeriveBunboArrList(int pMaxBunbo)
{
var AnswerBunboArrList = new List<int[]>();
var stk = new Stack<JyoutaiDef>();
JyoutaiDef WillPush;
WillPush.CurrVal = pMaxBunbo;
WillPush.BunboList = new List<int>() { pMaxBunbo };
stk.Push(WillPush);
while (stk.Count > 0) {
JyoutaiDef Popped = stk.Pop();
int Cnt = Popped.BunboList.Count;
if (Cnt == 12) {
int CompareResult = TaniBunsuuSumCompare2(Popped.BunboList);
if (CompareResult == 0) {
AnswerBunboArrList.Add(Popped.BunboList.ToArray());
}
continue;
}
for (int I = Popped.CurrVal - 1; 2 <= I; I--) {
WillPush.CurrVal = I;
WillPush.BunboList = new List<int>(Popped.BunboList) { I };
//2を超えたら枝切り
if (TaniBunsuuSumCompare2(WillPush.BunboList) == 1) break;
stk.Push(WillPush);
}
}
return AnswerBunboArrList;
}
//単位分数の和が
//2未満なら-1を返し
//2なら0を返し
//2超えなら1を返す
static int TaniBunsuuSumCompare2(List<int> pBunboList)
{
long Bunsi = 1;
long Bunbo = pBunboList[0];
for (int I = 1; I <= pBunboList.Count - 1; I++) {
Bunsi = Bunsi * pBunboList[I] + Bunbo;
Bunbo *= pBunboList[I];
//約分しておく
long GCD;
while ((GCD = DeriveGCD(Bunsi, Bunbo)) != 1) {
Bunsi /= GCD;
Bunbo /= GCD;
}
}
if (Bunbo * 2 < Bunsi) return 1;
if (Bunbo * 2 == Bunsi) return 0;
return -1;
}
//ユークリッドの互除法で2数の最大公約数を求める
static long DeriveGCD(long pVal1, long pVal2)
{
long WarareruKazu = Math.Max(pVal1, pVal2);
long WaruKazu = Math.Min(pVal1, pVal2);
while (true) {
long Amari = WarareruKazu % WaruKazu;
if (Amari == 0) return WaruKazu;
WarareruKazu = WaruKazu;
WaruKazu = Amari;
}
}
}
実行結果
分母の最大値=13で解を調査中。経過時間=00:00:00.0000022
分母の最大値=14で解を調査中。経過時間=00:00:00.0584775
分母の最大値=15で解を調査中。経過時間=00:00:00.0722496
分母の最大値=16で解を調査中。経過時間=00:00:00.0986656
分母の最大値=17で解を調査中。経過時間=00:00:00.1700269
分母の最大値=18で解を調査中。経過時間=00:00:00.3296547
分母の最大値=19で解を調査中。経過時間=00:00:00.6479627
分母の最大値=20で解を調査中。経過時間=00:00:01.3534502
分母の最大値=21で解を調査中。経過時間=00:00:02.7726870
分母の最大値=22で解を調査中。経過時間=00:00:05.6304477
分母の最大値=23で解を調査中。経過時間=00:00:11.4483178
分母の最大値=24で解を調査中。経過時間=00:00:21.8081091
分母の最大値=24で解を発見。経過時間=00:00:41.2632560
1/2 + 1/3 + 1/4 + 1/5 + 1/6 + 1/8 + 1/9 + 1/10 + 1/15 + 1/18 + 1/20 + 1/24 = 2
解説
分母の最大値を増やしながら、順に解の有無を調査してます。