トップページに戻る
次のC#のサンプルへ
前のC#のサンプルへ
8-21 小町算
問題
1□2□3□4□5□6□7□8□9 = 100
という数式の□の中に、
+,−,×,÷,空白
のいずれかを入れて数式を完成させます。
ソース
using System;
using System.Collections.Generic;
internal class CKabunSuu
{
private long mBunshi; //分子
private long mBunbo; //分母
//コンストラクタ (値指定)
internal CKabunSuu(long pBunshi, long pBunbo)
{
mBunshi = pBunshi;
mBunbo = pBunbo;
}
//コンストラクタ (インスタンス指定)
internal CKabunSuu(CKabunSuu pIns)
{
mBunshi = pIns.mBunshi;
mBunbo = pIns.mBunbo;
}
//加算用メソッド (インスタンス指定)
internal void Add(CKabunSuu pIns)
{
long SavedBunbo = mBunbo; //通分する前の分母
//通分してから、加算
mBunbo *= pIns.mBunbo;
mBunshi = this.mBunshi * pIns.mBunbo + pIns.mBunshi * SavedBunbo;
Yakubun();
}
//減算用メソッド (インスタンス指定)
internal void Subtract(CKabunSuu pIns)
{
Add(new CKabunSuu(-pIns.mBunshi, pIns.mBunbo));
}
//乗算用メソッド (インスタンス指定)
internal void Prod(CKabunSuu pIns)
{
this.mBunshi *= pIns.mBunshi;
this.mBunbo *= pIns.mBunbo;
Yakubun();
}
//除算用メソッド (インスタンス指定)
internal void Div(CKabunSuu pIns)
{
this.mBunshi *= pIns.mBunbo;
this.mBunbo *= pIns.mBunshi;
Yakubun();
}
//約分
private void Yakubun()
{
if (mBunshi == 0) return;
long GCD = DeriveGCD(mBunshi, mBunbo);
if (GCD == 1) return;
mBunshi /= GCD;
mBunbo /= GCD;
}
//ユークリッドの互除法で2数の最大公約数を求める
private long DeriveGCD(long pVal1, long pVal2)
{
pVal1 = Math.Abs(pVal1);
pVal2 = Math.Abs(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;
}
}
//分数の値を返す
internal decimal DecimalValue
{
get { return (decimal)mBunshi / mBunbo; }
}
}
class Program
{
static void Main()
{
var SuusikiList = new List<string>();
var Stk = new Stack<string>();
Stk.Push("1□2□3□4□5□6□7□8□9");
while (Stk.Count > 0) {
string Popped = Stk.Pop();
int Ind = Popped.IndexOf('□');
if (Ind == -1) {
SuusikiList.Add(Popped);
continue;
}
string wkStr = Popped.Remove(Ind, 1);
Stk.Push(wkStr);
Stk.Push(wkStr.Insert(Ind, "+"));
Stk.Push(wkStr.Insert(Ind, "-"));
Stk.Push(wkStr.Insert(Ind, "*"));
Stk.Push(wkStr.Insert(Ind, "/"));
}
int AnswerNo = 0;
foreach (string AnyStr in SuusikiList) {
if (CalcFromRPN(ToRPN(AnyStr)) == 100M)
Console.WriteLine("Answer{0} {1} = 100", ++AnswerNo, AnyStr);
}
}
//数式を逆ポーランド記法にした配列を返す
static string[] ToRPN(string pTargetStr)
{
var WillReturn = new List<string>();
var Stk = new Stack<string>();
string[] WkStrArr = MakeNumAndExpArr(pTargetStr);
foreach (string EachStr in WkStrArr) {
if (EachStr == "+" || EachStr == "-" || EachStr == "*" || EachStr == "/") {
int Priority = DerivePriority(EachStr);
while (Stk.Count > 0 && Priority <= DerivePriority(Stk.Peek())) {
WillReturn.Add(Stk.Pop());
}
Stk.Push(EachStr);
}
else WillReturn.Add(EachStr);
}
while (Stk.Count > 0) WillReturn.Add(Stk.Pop());
return WillReturn.ToArray();
}
//数式から数値と演算子の配列を作成
static string[] MakeNumAndExpArr(string pTargetStr)
{
var WillReturn = new List<string>();
var sb = new System.Text.StringBuilder();
foreach (Char EachChar in pTargetStr) {
if (EachChar == '+' || EachChar == '-' || EachChar == '*' || EachChar == '/') {
WillReturn.Add(sb.ToString()); sb.Length = 0;
WillReturn.Add(EachChar.ToString());
}
else sb.Append(EachChar);
}
WillReturn.Add(sb.ToString());
return WillReturn.ToArray();
}
//演算子のプライオリティを返す
static int DerivePriority(string pOperator)
{
if (pOperator == "+") return 1;
if (pOperator == "-") return 1;
if (pOperator == "*") return 2;
if (pOperator == "/") return 3;
return 0;
}
//逆ポーランド記法のListジェネリックを計算した結果を返す
static decimal CalcFromRPN(string[] pRPNArr)
{
var Stk = new Stack<CKabunSuu>();
foreach (string EachStr in pRPNArr) {
if (EachStr == "+" || EachStr == "-" || EachStr == "*" || EachStr == "/") {
CKabunSuu exp2 = Stk.Pop(); //exp2は中身を変更しないので参照でOK
CKabunSuu exp1 = new CKabunSuu(Stk.Pop());
if (EachStr == "+") { exp1.Add(exp2); Stk.Push(exp1); }
if (EachStr == "-") { exp1.Subtract(exp2); Stk.Push(exp1); }
if (EachStr == "*") { exp1.Prod(exp2); Stk.Push(exp1); }
if (EachStr == "/") { exp1.Div(exp2); Stk.Push(exp1); }
continue;
}
Stk.Push(new CKabunSuu(long.Parse(EachStr), 1));
}
return Stk.Pop().DecimalValue;
}
}
実行結果
省略
Answer96 12+34+5*6+7+8+9 = 100
Answer97 123-4-5-6-7+8-9 = 100
Answer98 123-45-67+89 = 100
Answer99 123+4*5-6*7+8-9 = 100
Answer100 123+4-5+67-89 = 100
Answer101 123+45-67+8-9 = 100
解説
数式を逆ポーランド記法に変換して、計算してます。
誤差防止のために仮分数クラスを使ってます。