トップページに戻る
次のC#のサンプルへ
前のC#のサンプルへ
遊び倒すガイド 中級編 1から9までの数字が1度ずつ現れる平方根
問題
344 という数は面白い性質を持っている。
344 の平方根を小数表示した sqrt(344) = 18.547236990・・・ は、
小数点を無視すると、先頭の9桁に1から9までの数字が1度ずつ現れる。
344 はこのような性質を持つ最も小さな整数である。
31078 もこの性質を持つ。sqrt(31078) = 176.28953457・・・である。
31078 はこの性質を持つ10番目に小さな整数である。
この性質を持つ160万番目に小さな整数を求めよ。
プロジェクトオイラーを遊び倒すガイド (中級編)
ソース
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
var sw = System.Diagnostics.Stopwatch.StartNew();
int OKCnt = 0;
long I = 1;
while (true) {
bool WillSkip;
long NextI;
if (IsOK(I, out WillSkip, out NextI)) {
OKCnt++;
if (OKCnt == 1 || OKCnt % 50000 == 0)
Console.WriteLine("{0}はOK,現在のOK数={1},経過時間={2}", I, OKCnt, sw.Elapsed);
if (OKCnt == 1600000) return;
}
if (WillSkip) I = NextI;
else I++;
}
}
static bool IsOK(long pTarget, out bool pWillSkip, out long pNextI)
{
pWillSkip = false;
double SqrtVal = Math.Sqrt(pTarget);
int Seisuubu = (int)Math.Truncate(SqrtVal);
pNextI = (long)(Seisuubu + 1) * (long)(Seisuubu + 1);
int KetasuuSeisuubu = DeriveKetasuu(Seisuubu);
double Jyousuu = DeriveJyousuu(KetasuuSeisuubu);
int Syousuubu = (int)((SqrtVal - Seisuubu) * Jyousuu);
int KetasuuSyousuubu = DeriveKetasuu(Syousuubu);
var NumList = new List<int>(9);
do {
int WillAdd = Seisuubu % 10;
if (WillAdd == 0 || NumList.Contains(WillAdd)) {
pWillSkip = true;
return false;
}
NumList.Add(WillAdd);
if (NumList.Count == 9) return true;
} while ((Seisuubu /= 10) > 0);
do {
int WillAdd = Syousuubu % 10;
if (WillAdd == 0) return false;
if (NumList.Contains(WillAdd)) return false;
NumList.Add(WillAdd);
if (NumList.Count == 9) return true;
} while ((Syousuubu /= 10) > 0);
return false;
}
static int DeriveKetasuu(int pVal)
{
if (pVal < 10) return 1;
if (pVal < 100) return 2;
if (pVal < 1000) return 3;
if (pVal < 10000) return 4;
if (pVal < 100000) return 5;
if (pVal < 1000000) return 6;
if (pVal < 10000000) return 7;
if (pVal < 100000000) return 8;
return 9;
}
static double DeriveJyousuu(int pVal)
{
if (pVal == 1) return 100000000D;
if (pVal == 2) return 10000000D;
if (pVal == 3) return 1000000D;
if (pVal == 4) return 100000D;
if (pVal == 5) return 10000D;
if (pVal == 6) return 1000D;
if (pVal == 7) return 100D;
return 10D;
}
}
実行結果
省略
3421224772はOK,現在のOK数=1400000,経過時間=00:02:56.8631831
3525089231はOK,現在のOK数=1450000,経過時間=00:03:02.9115144
3765028090はOK,現在のOK数=1500000,経過時間=00:03:09.1619161
3861202491はOK,現在のOK数=1550000,経過時間=00:03:15.4133262
3951343689はOK,現在のOK数=1600000,経過時間=00:03:21.6461511
解説
121の平方根は 11
144の平方根は 12
ですので、11のように、整数部だけでパンデジタル数でないことが確定する場合は、
整数部に1足した数の平方である144までループをSkipさせてます。