アプリ版:「スタンプのみでお礼する」機能のリリースについて

C言語のプログラミングの問題です。
1桁の整数4つをキーボードから入力して、四則演算で10になる式をすべて出力するという問題で、演算子の優先順位ありで、括弧は使わないとし、数字は入れ替え可能です。
また、プログラムはint型の変数を用いるというものです。
とりあえずは数字入れ替えなしで、次のような力技でソースコードを作ってみたのですが、数字の入れ替えまで考えるとあまりに力技すぎるようなだらだらとしたプログラムになってしまいます。。。
数字の入れ替え可能としてもっと簡単なプログラムを作るにはどのようなソースコードになるのでしょうか。

以下ソースコードです。

#include<stdio.h>
#include<math.h>

int main(void) {

int a, b, c, d = 0;

printf("一桁の整数4つを入力してください。\n");
scanf_s("%d %d %d %d", &a, &b, &c, &d);

if (a + b - c * 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 == 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 == 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 == 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 == 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 == 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 == 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 == 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 == 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 == 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 == 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 == 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 {
printf("10になる組み合わせはありません。");
}

return 0;

}

質問者からの補足コメント

  • 判定部分を関数にするとはどういうことでしょうか。swap関数を用いようかと思うのですが、2つの変数の値の交換はわかるのですが、4つの変数の値を交換する方法がわかりません、、、
    初歩的なことですみません、、、

    No.1の回答に寄せられた補足コメントです。 補足日時:2017/05/15 01:29
  • sub関数の呼び出しはどの部分で行えばいいのでしょうか?

    No.2の回答に寄せられた補足コメントです。 補足日時:2017/05/15 01:44
  • たびたびすみません^^;
    今回のプログラムでは、int型の変数のみの使用可という制約があり、浮動小数点に変換できないため、おっしゃるように、1/2が0扱いになるなどのように小数点以下が切り捨てられてしまい、計算が正確でなくなってしまいます、、、
    この制約がある限り、力技ではできないんですかね。。。

    No.3の回答に寄せられた補足コメントです。 補足日時:2017/05/15 02:30
  • int型のみだと、計算上で1/2(=0.5)や3/4(=0.75)などが、小数点以下切り捨てにより0になってしまうので、商に0.5をさらに足すことで、小数点以下切り捨てでも四捨五入と同じ条件になるようにました。
    例えば、a + (b * c / d + 0.5) のような感じです。
    ただ、a * b - (c / d + 0.5) など、商を除算する場合、0.5余分に引いてしまうため、
    例えば3 * 4 - (8 / 5 + 0.5) の場合、12 - 2.1 = 9.9 ≒ 9となってしまいます。
    故にa * b - (c / d + 0.5) + 0.5 と、0.5を後で加えることで、
    上の例の場合、3 * 4 - (8 / 5 + 0.5) + 0.5 = (12 - 2.1) + 0.5 = 10.4 ≒ 10 とでき、
    この問題点を解消しました。

    No.6の回答に寄せられた補足コメントです。 補足日時:2017/05/16 00:10
  • 1) 同じ値は複数あってもよいとしています。
    2) 演算子は重複使用不可です。
    3) 計算結果は算術的に10になることです。
    3)に関しては、No.6さんに対する補足コメントにて、自分なりにソースコードに修正を加えた説明を述べているので、そちらも目を通して下さいますようお願いします。

    No.7の回答に寄せられた補足コメントです。 補足日時:2017/05/16 00:21
  • 算術的に10.0以上かつ11未満でOKということです。

    No.9の回答に寄せられた補足コメントです。 補足日時:2017/05/16 01:05
  • (小数点以下が無視される)int型の変数のみを使ったプログラムという指定があったので、私が算術的に10.0以上かつ11未満という条件だと思って解きました。

    No.11の回答に寄せられた補足コメントです。 補足日時:2017/05/21 08:39

A 回答 (15件中1~10件)

No14です。


calcに一部誤りがありましたので、修正しました。
下記URLが正しいソースになります。こちらを使用してください。
http://climbi.com/b/10192/1
不明点があれば、補足してください。
    • good
    • 0

No12をベースにして、作成した解法が以下のソースになります。


文字数オーバーなので下記URLに記述しました。
http://climbi.com/b/10192/0

calcは入力値 p1,p2,p3,p4に対して演算子を組み合わせた24ケースを全て行います。
10になるかどうかの判定は、答え(ans)が10であり、余り(mod)が0であることです。
これは、Hanteiで行っています。

mainでは、入力値 p1,p2,p3,p4をValueSwapに渡していますが、
入力値の組み合わせをそのまま実行するなら、入力値 p1,p2,p3,p4をcalcに渡せば、それで可能です。
ValueSawapでは、p1 p2 p3 p4の全パターンの組み合わせを作り出しますが、重複したパターンの場合は、
重複したものは、呼び出さないようにしています。

p1=1 p2=1 P3=3 p4=4のとき
1 1 3 4 (先頭がp1)
1 1 3 4 (先頭がp2)とは同じになります。この場合は、2回目の1 1 3 4ではcalcを呼び出さないようにしています。

下記が入力値 1 2 3 4のときの実行結果です。
------------------------------------------
p1 p2 p3 p4=>1 2 3 4
p1=1 p2=2 p3=3 p4=4

1 回目成立
2 / 1 * 3 + 4 = 10
2 回目成立
2 * 3 / 1 + 4 = 10
3 回目成立
2 * 3 + 4 / 1 = 10
4 回目成立
2 * 4 - 1 + 3 = 10
5 回目成立
2 * 4 + 3 - 1 = 10
6 回目成立
3 - 1 + 2 * 4 = 10
7 回目成立
3 / 1 * 2 + 4 = 10
8 回目成立
3 - 1 + 4 * 2 = 10
9 回目成立
3 / 1 * 4 - 2 = 10
10 回目成立
3 * 2 / 1 + 4 = 10
11 回目成立
3 + 2 * 4 - 1 = 10
12 回目成立
3 + 2 * 4 / 1 = 10
13 回目成立
3 * 2 + 4 / 1 = 10
14 回目成立
3 * 4 / 1 - 2 = 10
15 回目成立
3 + 4 * 2 - 1 = 10
16 回目成立
3 + 4 * 2 / 1 = 10
17 回目成立
3 * 4 - 2 / 1 = 10
18 回目成立
4 / 1 + 2 * 3 = 10
19 回目成立
4 / 1 + 3 * 2 = 10
20 回目成立
4 / 1 * 3 - 2 = 10
21 回目成立
4 + 2 / 1 * 3 = 10
22 回目成立
4 * 2 - 1 + 3 = 10
23 回目成立
4 * 2 + 3 - 1 = 10
24 回目成立
4 + 3 / 1 * 2 = 10
25 回目成立
4 * 3 / 1 - 2 = 10
26 回目成立
4 * 3 - 2 / 1 = 10

26回成立しました。
    • good
    • 0
この回答へのお礼

こちらでもありがとうございました! 参考にさせていただき、今一度考えてみます!

お礼日時:2017/05/25 01:30

No12です。

すみません。
もし、
void ValueSwap(int p1,int p2,int p3,int p4)でエラーになるようなら、
最初の箇所を
void ValueSwap(int p1,int p2,int p3,int p4)
{
int x[4];
int d[4];
int ix[4];
int i,j,k,l;
int ctr = 0;
x[0] = p1;・・・・①
x[1] = p2;・・・・②
x[2] = p3;・・・・③
x[3] = p4;・・・・④
for (i = 0; i < 4; i++){

のようにしてください。(①②③④の箇所を移動する)
    • good
    • 0

ソースが多いので2回になります。


まず、以下のプログラムを実行してください。
-------------------------------------
#include<stdio.h>
void ValueSwap(int p1,int p2,int p3,int p4)
{
int x[4];
x[0] = p1;
x[1] = p2;
x[2] = p3;
x[3] = p4;
int d[4];
int ix[4];
int i,j,k,l;
int ctr = 0;
for (i = 0; i < 4; i++){
d[0] = x[i];
ix[0] = i;
for(j = 0; j < 4; j++){
if (ix[0] != j){
d[1] = x[j];
ix[1] = j;
for(k = 0; k < 4; k++){
if (ix[0] != k && ix[1] != k){
d[2] = x[k];
ix[2] = k;
for(l = 0; l < 4; l++){
if (ix[0] != l && ix[1] != l && ix[2] != l){
d[3] = x[l];
ix[3] = l;
ctr++;
printf("%2d:%d %d %d %d \n",ctr,d[0],d[1],d[2],d[3]);
//calc(d[0],d[1],d[2],d[3]);
}
}
}
}
}
}
}
}
void EnzanSwap(void)
{
int i,j,k;
int ctr = 0;
char E[3];
char X[] = "+-*/";
for (i = 0;i < 4; i++){
E[0] = X[i];
for(j = 0; j < 4; j++){
if(E[0] != X[j]){
E[1] = X[j];
for(k = 0;k < 4; k++){
if(E[0] != X[k] && E[1] != X[k]){
E[2] = X[k];
ctr++;
printf("%2d:%c%c%c\n",ctr,E[0],E[1],E[2]);
}
}
}
}
}
}
int main (void)
{
EnzanSwap();
printf("---------------------\n");
ValueSwap(1,2,3,4);
}
------------------------------------------
EbzanSwapは、4つの演算子(+,-,*,/)を3回取り出す時の、全てのパターンを網羅しています。
つまり、入力値が、p1,p2,p3,p4の場合、
p1□p2□p3□p4  の□に4つの演算子(+,-,*,/)を組み合わせる全てのパターンを網羅しています。
このパターンに従い、演算を行うプログラムを書けば良いことになります。
但し、割り算の後に、掛け算がくる場合は、掛け算を先に行い、のちに割り算を行うようにします。
例 p1/p2*p3+p4 は p1*p3/p2+p4 にして計算する。
更に、この結果が10であればOKであるが、正確にはもう1つ条件があり、
割り算の結果がきちんと割り切れる必要があるということです。
これは、5+6-9/9 はOKであるが5+6-9/8はNGになります。
答え=5+6-9/9;
答え=5+6-9/8;
両方とも答えは10ですが、9/8は、余りが発生します。(整数で割り切れません)
従って、割り算の余りがあるかどうかで割り切れたかどうかを判断します。

ValueSwapは、入力された値(例 1 2 3 4)を演算するときに、組み合わせ可能な
全てのパターンを網羅します。
1□2□3□4
1□2□4□3
などの全てのパターンを作り出します。そのパターンにしたがい、計算処理を呼び出せば良いことになります。

下記が、実行結果です。
1:+-*
2:+-/
3:+*-
4:+*/
5:+/-
6:+/*
7:-+*
8:-+/
9:-*+
10:-*/
11:-/+
12:-/*
13:*+-
14:*+/
15:*-+
16:*-/
17:*/+
18:*/-
19:/+-
20:/+*
21:/-+
22:/-*
23:/*+
24:/*-
---------------------
1:1 2 3 4
2:1 2 4 3
3:1 3 2 4
4:1 3 4 2
5:1 4 2 3
6:1 4 3 2
7:2 1 3 4
8:2 1 4 3
9:2 3 1 4
10:2 3 4 1
11:2 4 1 3
12:2 4 3 1
13:3 1 2 4
14:3 1 4 2
15:3 2 1 4
16:3 2 4 1
17:3 4 1 2
18:3 4 2 1
19:4 1 2 3
20:4 1 3 2
21:4 2 1 3
22:4 2 3 1
23:4 3 1 2
24:4 3 2 1
    • good
    • 0

>算術的に10.0以上かつ11未満でOKということです。



本当にそうですか。
もし、そうならあなたの方法が正しいかもしれませんが、そのような条件で出題を行う出題者のセンスを疑います。
ほんとうに算術的に10.0以上かつ11未満でOKなら、以下は無視してください。

算術的に10丁度(10.3等はNG)がOKということなら、その解法が提示できますが、いかがでしょうか。
考え方としては
1)/の演算の後に*があるなら、*を先にする。
例 4 / 3 * 6 ==> 4 * 6 / 3 にする
2)/で割り切れるかチェックする。
余りが0なら割り切れる。
例 2 + 4 / 3 * 6 = 10(OK)
例 4 + 4 / 3 *5 = 10.66666(NG) (4*5%3は0にならない。)
となります。
この回答への補足あり
    • good
    • 0

ところで


3*4-7/5
は OK でしょうかそれともアウトでしょうか?
    • good
    • 0

>例えば3 * 4 - (8 / 5 + 0.5) の場合、12 - 2.1 = 9.9 ≒ 9となってしまいます。


>故にa * b - (c / d + 0.5) + 0.5 と、0.5を後で加えることで、
>上の例の場合、3 * 4 - (8 / 5 + 0.5) + 0.5 = (12 - 2.1) + 0.5 = 10.4 ≒ 10 とでき、
>この問題点を解消しました。

これは、だめだと思いますが。
3*4-8/5 は、算術的には 12-1.6=10.4 ですから算術的に10になりませんよね。
算術的に10になるものが求める答えなのではないでしょうか。
それとも、算術的に10.0以上かつ11未満ならOKということでしょうか?
この回答への補足あり
    • good
    • 0

>この問題点を解消しました。



おお、四捨五入に0.5 を使い、浮動小数点の変数を使わずに解けちゃいましたか!

うちの会社に来ます?

※ただ、四捨五入していいもんかどうかも回答条件としてあるのかどうか、
仕事だと「勝手に解釈したのか」とどやされるところなんですが・・・。

ま、いいか。いいな。いいよ。

とにかく自己解決、おめでとうございます。
    • good
    • 0
この回答へのお礼

解答条件に、小数点以下を四捨五入としてよいのか指定がなかったので、とりあえずは算術的に四捨五入するものと考えるのが、実用的でもあり、最善と思い、このような解決法に至りました。。。^^;
おかげさまでいろいろと考え付くことができるきっかけとなりました。ご協力してくださり、ありがとうございます!

お礼日時:2017/05/16 00:58

補足要求です。


1)入力された数値は、同じ値が複数あってもよいのですか。例(1,1,2,2等)
2)演算子は、同じものは使わない前提ですか。
  例 a+b+c+dは考慮しない。
3)計算結果は、算術的に10になることですか。
  それともC言語で実行した結果で10になることですか。
  例 1+3/7*7 = 4(算術的)
  例 1+3/7*7 = 1(C言語で実行した結果)
この回答への補足あり
    • good
    • 0

ごめんなさい。

 やっぱし駄目ですは。

「整数の演算として答えとして10になればよい」という条件か確認したほうがいいですね。

たとえば、

7 * 8 / 5 + 5

の答えは 10 でいいのか、悪いのか。

もし、「10です」ということならば、No.5 氏の答えは無視でいいでしょう(笑)。
「だってそのまま計算したら10じゃないんだもーん」ということで。

----余談----
整数で計算するのに小数点以下も考慮しなさい、ってことならなんか、「小数点有りフラグ」みたいなのが必要になってくるし、そこまでくると設問自体が成立してないんじゃないか、ってことになりますもんね。

まさか、「そろばん塾」でやってるような方法をプログラムで実現するの?という話で。
この回答への補足あり
    • good
    • 0

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