トップページに戻る
次のC#のサンプルへ
前のC#のサンプルへ
Cマガ電脳クラブ(第120回) 素性のよい整数たち
問題
ここに相異なる7数がある。そのうちの6数を選んでかけ合わせ,
それに残りの1数を足すと素数になり,これはどの6数を選んでも成立しているという。
このような7数の組み合わせはたくさんあるので,その7数の和が最小のものを見つけていただきたい。
なお,ここに登場する数はすべて正の整数とする。
ソース
using System;
using System.Collections.Generic;
class Program
{
const int Jyougen = 100; //7数の和の仮の上限
struct JyoutaiDef
{
internal int CurrVal;
internal int SumVal;
internal List<int> ValList;
internal bool HasGuusuu; //偶数は7個の中で1つ
}
static void Main()
{
Console.WriteLine("7数の和が、{0}以下となる組み合わせを検証します。", Jyougen);
var stk = new Stack<JyoutaiDef>();
JyoutaiDef WillPush;
for (int I = 1; I <= Jyougen; I++) {
WillPush.CurrVal = I;
WillPush.SumVal = I;
WillPush.ValList = new List<int>() { I };
WillPush.HasGuusuu = (I % 2 == 0);
stk.Push(WillPush);
}
int AnswerSumVal = Jyougen;
while (stk.Count > 0) {
JyoutaiDef Popped = stk.Pop();
if (AnswerSumVal < Popped.SumVal) continue;
if (Popped.HasGuusuu && Popped.ValList.Count == 7) {
if (IsOK(Popped.ValList) == false) continue;
Console.WriteLine("和が{0}の解候補を発見しました。", Popped.SumVal);
Popped.ValList.ForEach(X => Console.Write("{0},", X));
Console.WriteLine();
AnswerSumVal = Popped.SumVal;
continue;
}
for (int I = Popped.CurrVal + 1; I <= Jyougen; I++) {
//和が上限を超えたら枝切り
if (AnswerSumVal < Popped.SumVal + I) break;
//偶数を2つ以上含んだら枝切り
if (Popped.HasGuusuu && I % 2 == 0) continue;
//既存の数リストと、互いに素でなかったら枝切り
if (Popped.ValList.Exists(X => DeriveGCD(X, I) > 1)) continue;
WillPush.CurrVal = I;
WillPush.SumVal = Popped.SumVal + I;
WillPush.ValList = new List<int>(Popped.ValList) { I };
WillPush.HasGuusuu = Popped.HasGuusuu || (I % 2 == 0);
stk.Push(WillPush);
}
}
}
//ユークリッドの互除法で2数の最大公約数を求める
static int DeriveGCD(int pVal1, int pVal2)
{
int WarareruKazu = Math.Max(pVal1, pVal2);
int WaruKazu = Math.Min(pVal1, pVal2);
while (true) {
int Amari = WarareruKazu % WaruKazu;
if (Amari == 0) return WaruKazu;
WarareruKazu = WaruKazu;
WaruKazu = Amari;
}
}
static bool IsOK(List<int> pValList)
{
for (int I = 0; I <= pValList.Count - 1; I++) {
long wkLongVal = 1;
for (int J = 0; J <= pValList.Count - 1; J++) {
if (J == I) continue;
wkLongVal *= pValList[J];
}
wkLongVal += pValList[I];
if (IsPrime(wkLongVal) == false) return false;
}
return true;
}
//素数かを判定
static bool IsPrime(long pTarget)
{
for (long I = 2L; I * I <= pTarget; I++) {
if (pTarget % I == 0L) return false;
}
return true;
}
}
実行結果
7数の和が、100以下となる組み合わせを検証します。
和が80の解候補を発見しました。
1,4,7,11,13,15,29,
和が78の解候補を発見しました。
1,3,8,11,13,17,25,
和が78の解候補を発見しました。
1,3,5,7,17,22,23,
解説
A,B,C,D,E,F,G の中でAとBが偶数だとすると、
B*C*D*E*F*Gは、偶数であり、(偶数に自然数を掛けると偶数のため)
A+B*C*D*E*F*Gも偶数です。 (偶数に偶数を加算すると偶数のため)
よって、偶数が2つ以上でないことを、枝切り条件としてます。
A,B,C,D,E,F,G の中でAとBが互いに素でないとすると、
A+B*C*D*E*F*G は、A+Bの共通の約数の倍数なので素数でないです。
よって、7つの数が互いに素であることを、枝切り条件としてます。
A,B,C,D,E,F,G が全て奇数だとすると
A+B*C*D*E*F*Gが偶数になるため (奇数同士の積は奇数であり、奇数同士の和は偶数のため)
偶数が1つ含むことを、条件としてます。