From toge@hydoru.or.jp Fri May 14 02:57:13 1999 Received: from wise19.mn.waseda.ac.jp (wise19.mn.waseda.ac.jp [133.9.4.137]) by newton.kashi.info.waseda.ac.jp (8.8.8/3.7W) with ESMTP id CAA02953 for ; Fri, 14 May 1999 02:57:12 +0900 (JST) Received: from wise20.mn.waseda.ac.jp (wise20.mn.waseda.ac.jp [133.9.4.141]) by wise19.mn.waseda.ac.jp (8.9.1a/3.7W-19980811) with ESMTP id CAA25564 for ; Fri, 14 May 1999 02:46:16 +0900 (JST) Received: from wise13.mn.waseda.ac.jp (wise13.mn.waseda.ac.jp [133.9.4.145]) by wise20.mn.waseda.ac.jp (8.9.1+3.0W/3.7W-19981111) with ESMTP id CAA29316 for ; Fri, 14 May 1999 02:46:16 +0900 (JST) Received: from ushiku.hydoru.or.jp (IDENT:toge@max2-ppp16.tsukuba.sannet.ne.jp [202.216.4.23]) by wise13.mn.waseda.ac.jp (8.9.1a/3.7W-19980811) with ESMTP id CAA12971 for ; Fri, 14 May 1999 02:46:14 +0900 (JST) Received: (from toge@localhost) by ushiku.hydoru.or.jp (8.9.3/3.7W1.0) id CAA01920; Fri, 14 May 1999 02:43:57 +0900 Date: Fri, 14 May 1999 02:43:57 +0900 Message-Id: <199905131743.CAA01920@ushiku.hydoru.or.jp> From: To: kashi@mn.waseda.ac.jp Subject: [JSJ] User-Agent: WEMI/1.13.3 (Yaizu) FLIM/1.12.5 (Hirahata) MULE XEmacs/21.0 (beta67) (20 minutes to Nikko) (i586-pc-linux) MIME-Version: 1.0 (generated by WEMI 1.13.3 - "Yaizu") Content-Type: text/plain; charset=ISO-2022-JP Status: OR G97P0751 橋本拓也 mailto : g97p0751@mn.waseda.ac.jp 1999/04/23 分「切符の番号で10を作る 」のソースです。 /* 切符問題を解く */ #include #include #include /* bool型 */ typedef int bool; #define false 0 #define true ~false /* 分数を表現する構造体 */ typedef struct { int num; /* 分子 */ int deno; /* 分母 */ } Frac; /* 演算子 */ enum { ADD = 0 + 1024, DEC = 1 + 1024, MUL = 2 + 1024, DIV = 3 + 1024 }; /* プロトタイプ宣言 */ void usage(char []); int MakeCombination(int []); int AddOperator(int []); int ArrangeData(int [], int []); bool CheckValidData(int []); void ShowExpr(int []); int main(int argc, char *argv[]) { int data[4]; int i; /* パラメーターが足りなかったら使い方を表示 */ if (argc != 5) { usage(argv[0]); return 1; } /* パラメーターを数値化 */ for (i = 0; i < 4; i++) data[i] = atoi(argv[i+1]); /* 指定された数値の組合わせを作成 */ printf("%d patterns\n", MakeCombination(data)); return 0; } /* 使い方を説明 */ void usage(char name[]) { printf("usage : %s [0-9] [0-9] [0-9] [0-9]\n", name); } /* 組合わせを生成 */ int MakeCombination(int data[]) { int i, j, k, l; int num = 0; for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) { if (j == i) continue; for (k = 0; k < 4; k++) { if (k == i || k == j) continue; for (l = 0; l < 4; l++) { if (l == i || l == j || l == k) continue; else { /* 数値の順番が決定 */ int Comb[4] = {data[i], data[j], data[k], data[l]}; num += AddOperator(Comb); } } } } } return num; } /* 演算子3つを追加 */ int AddOperator(int data[]) { int i, j, k; int num = 0; for (i = ADD; i <= DIV; i++) { for (j = ADD; j <= DIV; j++) { for (k = ADD; k <= DIV; k++) { /* 演算子が決定 */ int Op[3] = {i, j, k}; num += ArrangeData(data, Op); } } } return num; } /* 数値と演算子の配置を総当たりで計算 */ int ArrangeData(int data[], int op[]) { /* 逆ポーランド法での表記を考えているので数値と演算子の配置のパターンは以下の5通り * (n1/n2/n3/n4 が数値, op1/op2/op3 が演算子) * n1 n2 n3 n4 op1 op2 op3 * n1 n2 op1 n3 n4 op2 op3 * n1 n2 n3 op1 n4 op2 op3 * n1 n2 n3 op1 op2 n4 op3 * n1 n2 op1 n3 op2 n4 op3 * このうち先頭の2つの項目と最後の一つの項目は常に等しい。 */ int expr[7] = {data[0], data[1], 0, 0, 0, 0, op[2]}; int num = 0; expr[2] = data[2]; expr[3] = data[3]; expr[4] = op[0]; expr[5] = op[1]; if(CheckValidData(expr)) num++; expr[2] = data[2]; expr[3] = op[0]; expr[4] = data[3]; expr[5] = op[1]; if(CheckValidData(expr)) num++; expr[2] = op[0]; expr[3] = data[2]; expr[4] = data[3]; expr[5] = op[1]; if(CheckValidData(expr)) num++; expr[2] = data[2]; expr[3] = op[0]; expr[4] = op[1]; expr[5] = data[3]; if(CheckValidData(expr)) num++; expr[2] = op[0]; expr[3] = data[2]; expr[4] = op[1]; expr[5] = data[3]; if(CheckValidData(expr)) num++; return num; } /* 式の値が10になるか計算 */ bool CheckValidData(int expr[]) { int pos = 0; Frac stack[5]; int i; for (i = 0; i < 7; i++) { if (expr[i] & 1024) { pos--; switch(expr[i]) { case ADD: stack[pos-1].num = stack[pos-1].deno * stack[pos].num + stack[pos].deno * stack[pos-1].num; stack[pos-1].deno = stack[pos-1].deno * stack[pos].deno; break; case DEC: stack[pos-1].num = stack[pos].deno * stack[pos-1].num - stack[pos-1].deno * stack[pos].num; stack[pos-1].deno = stack[pos-1].deno * stack[pos].deno; break; case MUL: stack[pos-1].num *= stack[pos].num; stack[pos-1].deno *= stack[pos].deno; break; case DIV: /* 0で割らないように注意 */ if (!(stack[pos-1].num)) return false; stack[pos-1].num *= stack[pos].deno; stack[pos-1].deno *= stack[pos].num; break; } } else { stack[pos].num = expr[i]; stack[pos].deno = 1; pos++; } } /* スタックの先頭の値が 10 になっていることを確認 */ if (stack[pos-1].num == stack[pos-1].deno * 10) { /* 10 になっていればその式を表示 */ ShowExpr(expr); return true; } return false; } /* 逆ポーランドでの表記を通常の式表記で表示 */ void ShowExpr(int expr[]) { char stack[5][15]; int pos = 0; int i; for (i = 0; i < 7; i++) { /* 演算子だった場合にはスタックの上二つを結合して積む */ if (expr[i] & 1024) { bool insertbrase = true; char op; pos--; switch(expr[i]) { case ADD: op = '+'; break; case DEC: op = '-'; break; case MUL: op = '*'; break; case DIV: op = '/'; break; } /* 最後の演算子だった場合には括弧をつけない*/ if (i == 6) insertbrase = false; /* 括弧をいれる場合 */ if (insertbrase) { char tmp1[15]; char tmp2[2] = {op, '\0'}; strcpy(tmp1, stack[pos-1]); strcpy(stack[pos-1], "("); strcat(stack[pos-1], tmp1); strcat(stack[pos-1], tmp2); strcat(stack[pos-1], stack[pos]); strcat(stack[pos-1], ")"); } /* 括弧をいれない場合 */ else { char tmp[2] = {op, '\0'}; strcat(stack[pos-1], tmp); strcat(stack[pos-1], stack[pos]); } } /* 値だった場合には分数に展開して積む */ else { stack[pos][0] = (char)expr[i] + '0'; stack[pos][1] = '\0'; pos++; } } printf("%s\n", stack[pos-1]); }