プロが教えるわが家の防犯対策術!

C言語で、一桁の整数4つをキーボードから入力し、四則演算により答えが10になる全ての式を出力するプログラムを作成するというものです。
条件として、
・演算子には優先順位があるものとする
・同じ演算子は使用不可
・カッコを用いた計算方法は考えない
→例 (1+2)*4=12など
・int型の変数のみ使用可
です。
以下の様に、全パターンをひとつづつ試行して、10になるかどうか判定するというような力技のプログラムを作ったのですが、もっと簡単なプログラムにするにはどのようなソースコードにすればいいのでしょうか?
以下、力技で作ったプログラムのソースコードです。

・・・ソースコード・・・
#include<stdio.h>
#include<math.h>

///式を計算する関数を作る。///
void sub(int a, int b, int c, int d) {

///重複なしで演算子の全ての組み合わせを試行し、10になれば式を表示///
if (a + b - c * d == 10)
printf("%d+%d-%d*%d\n", a, b, c, d);
else if (a + (b - (c / d + 0.5) + 0.5) == 10) ///0.5多く引いているので0.5を加える///
printf("%d+%d-%d/%d\n", a, b, c, d);
else if (a + b * c - d == 10)
printf("%d+%d*%d-%d\n", a, b, c, d);
else if (a + (b * c / d + 0.5) == 10) ///商には0.5を加えてから小数点以下切り捨て=四捨五入///
printf("%d+%d*%d/%d\n", a, b, c, d);
else if (a + (b / c +0.5) - d == 10)
printf("%d+%d/%d-%d\n", a, b, c, d);
else if (a + (b / c + 0.5) * d == 10)
printf("%d+%d/%d*%d\n", a, b, c, d);
else if (a - b + c * d == 10)
printf("%d-%d+%d*%d\n", a, b, c, d);
else if (a - b + (c / d + 0.5) == 10)
printf("%d-%d+%d/%d\n", a, b, c, d);
else if (a - b * c + d == 10)
printf("%d-%d*%d+%d\n", a, b, c, d);
else if (a - (b * c / d + 0.5) == 10)
printf("%d-%d*%d/%d\n", a, b, c, d);
else if ((a - (b / c + 0.5) + 0.5) + d == 10)
printf("%d-%d/%d+%d\n", a, b, c, d);
else if (a - (b / c * d + 0.5) == 10)
printf("%d-%d/%d*%d\n", a, b, c, d);
else if (a * b + c - d == 10)
printf("%d*%d+%d-%d\n", a, b, c, d);
else if (a * b + (c / d + 0.5) == 10)
printf("%d*%d+%d/%d\n", a, b, c, d);
else if (a * b - c + d == 10)
printf("%d*%d-%d+%d\n", a, b, c, d);
else if (a * b - (c / d + 0.5) + 0.5 == 10)
printf("%d*%d-%d/%d\n", a, b, c, d);
else if ((a * b / c + 0.5) + d == 10)
printf("%d*%d/%d+%d\n", a, b, c, d);
else if ((a * b / c + 0.5) - d == 10)
printf("%d*%d/%d-%d\n", a, b, c, d);
else if ((a / b + 0.5) + c - d == 10)
printf("%d/%d+%d-%d\n", a, b, c, d);
else if ((a / b + 0.5) + c * d == 10)
printf("%d/%d+%d*%d\n", a, b, c, d);
else if ((a / b + 0.5) - c + d == 10)
printf("%d/%d-%d+%d\n", a, b, c, d);
else if ((a / b + 0.5) - c * d == 10)
printf("%d/%d-%d*%d\n", a, b, c, d);
else if ((a / b * c + 0.5) + d == 10)
printf("%d/%d*%d+%d\n", a, b, c, d);
else if ((a / b * c + 0.5) - d == 10)
printf("%d/%d*%d-%d\n", a, b, c, d);
else { ///全ての条件を満たさなければ何も返さない///
return;
}
}

int main(void) {

///値を格納する変数を0に初期化///
int a, b, c, d = 0;

printf("一桁の整数4つを入力してください。\n");

///1桁の整数4つを入力///
scanf_s("%d %d %d %d", &a, &b, &c, &d);

printf("\n");

///関数呼び出し///
sub(a, b, c, d); ///1桁の整数4つの組み合わせを試行///
sub(a, b, d, c);
sub(a, c, b, d);
sub(a, c, d, b);
sub(a, d, b, c);
sub(a, d, c, b);
sub(b, a, c, d);
sub(b, a, d, c);
sub(b, c, a, d);
sub(b, c, d, a);
sub(b, d, a, c);
sub(b, d, c, a);
sub(c, a, b, d);
sub(c, a, d, b);
sub(c, b, a, d);
sub(c, b, d, a);
sub(c, d, a, b);
sub(c, d, b, a);
sub(d, a, b, c);
sub(d, a, c, b);
sub(d, b, a, c);
sub(d, b, c, a);
sub(d, c, a, b);
sub(d, c, b, a);

return 0;

}

A 回答 (2件)

* 一桁の整数4つ、全パターン


int[4] から 4 個とる順列
同じものを含む順列の可能性あるので、重複は除く処理が必要

* 同じ演算子は使用不可、カッコを用いた計算方法は考えない
"+,-,*,/" の 4 個から 3 個とる順列

* int型の変数のみ使用可
整数 2 個で一つの値を表現する有理数で計算する
// 足し算の処理サンプル
typedef struct { int a, b; } rat_num;
rat_num v = {1,3}, w = {3,1};
v.a = v.a * w.b + w.a * v.b;
v.b = v.b * w.b;
printf("%d\n", v.a / v.b);

* 演算子には優先順位がある
LL(1)文法で構文解析する
// 構文例
expr0 := expr1 ( ('+'|'-') expr1 )*
expr1 := expr2 ( ('*'|'/') expr2 )*
expr2 := number
// それぞれに対応する関数を作る
typedef struct { int *nums, *oprs, index, size; } context;
ret_num calc_expr0(context* p); // calc_expr1 で得た値を加算減算する
ret_num calc_expr1(context* p); // calc_expr2 で得た値を乗算除算する
ret_num calc_expr2(context* p); // 現在の位置の数値を得る
// calc_expr0 を実行することで、数式の計算結果を得られる

* 同じものを含む順列
再帰ですべての組み合わせを求める
// 処理例
void permutate(int a[], int s, int t, int n) {
_ int i, j, f, v;
_ if (n < t) {
_ _ v = a[n];
_ _ for (i=n; i<s; i++) {
_ _ _ for (f=0, j=n; j<i; j++) f |= (a[j] == a[i]);
_ _ _ if (f) continue; // 重複させない
_ _ _ a[n] = a[i]; a[i] = v;
_ _ _ permutate(a, s, t, n+1);
_ _ _ a[i] = a[n]; a[n] = v;
_ _ }
_ } else {
_ _ 出力(a, t);
_ }
}
    • good
    • 0
この回答へのお礼

遅くなりました、ご回答ありがとうございます。
そのように考えていくんですね、参考にしたいと思います。

お礼日時:2017/08/07 13:45

一応、つっこんでおくと



C言語では、
・計算は、演算子一つずつ順番にやります。
・int / int = int です。小数以下は出ません。
・int + double = double です。
・double == int の比較は int → double の型変換が行われて double == double の比較 です。

> else if (a + (b * c / d + 0.5) == 10) ///商には0.5を加えてから小数点以下切り捨て=四捨五入///

では
int t1,t2 ;
double s1,s2 ;
t1 = b*c ; /* int * int = int */
t2 = t1/ d ; /* b * c / d : int / int = int 端数は出ない */
s1 =(double)t2 + 0.5 ; /* b * c / d + 0.5 : int + double = double 整数に+0.5しただけ */
s2 = (double)a + s1 ; /* a + (b * c / d + 0.5) : int + double = double */
if ( s2 == (double)10 ) { /* double == int は double == double で比較。doubleをintに切り捨てたりしない */

と同等になります。
///商には0.5を加えてから小数点以下切り捨て=四捨五入///
なんてことにはなりません。
他も同様です。


スマートにやるなら次のようになるでしょう。
(1)入力した4値の全ての順列パターンに対してループさせる
(2)4つ演算子の全ての順列パターンに対してループさせる
(3) (1),(2)で求めた 4つの値と4つの演算子から式を作り、それを解析して、解析木を作り、計算する。
(4)計算は分数で行う

全体としてはシンプルですが、それぞれの処理が複雑になります。
    • good
    • 0
この回答へのお礼

遅くなりました、、ご回答ありがとうございます。
なるほど、、参考にさせていただき、試してみます。

お礼日時:2017/08/07 13:44

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!