B:(2,3,1),A:(2,1,1), B:(0,1,1),A:(0,0,1), B:(0,0,0)でBの勝ちです.
0 0 1 0 + 0 1 1 0 ------------ 1 0 0 0
0 0 1 0 ^ 0 1 1 0 ------------ ? ? ? ?
A | B | A^B |
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 0 |
5: 1 0 1 4: 1 0 0 1: 0 0 1 --------------- 0 0 0
x = a[0] ^ a[1] ^ a[2]x == 0 のとき必勝形です。
a[i] ^ x a[0] = (1,0,1) (1,1,0) a[1] = (0,1,1) > (1,0,1) a[2] = (1,0,0) (1,1,0) x = (0,1,0)
/*********************************************************** nim.c -- 三山くずし ***********************************************************/ #include <stdio.h> #include <stdlib.h> //奥村著:アルゴリズム辞典より void main() { int a[4], i, j, imax, max, n, r, x, my_turn; for (i = 1; i <= 3; i++) { printf("%d 番の山の石の数? ", i); scanf("%d", &a[i]); if (a[i] <= 0) return EXIT_FAILURE; } for (my_turn = 1; 1; my_turn ^= 1) { max = 0; for (i = 1; i <= 3; i++) { printf(" %d ", i); for (j = 1; j <= a[i]; j++) printf("*"); printf("\n"); if (a[i] > max) {//maxは最大値 max = a[i]; imax = i; } } if (max == 0) break;//繰り返し終了 if (my_turn) { printf("私の番です.\n"); x = a[1] ^ a[2] ^ a[3]; /* 排他的論理和 */ j = 0; for (i = 1; i <= 3; i++) if (a[i] > (a[i] ^ x)) j = i;//jから石を取る if (j != 0) a[j] ^= x; else a[imax]--;//必勝形になっている場合 } else {//相手の番 do { printf("何番の山からとりますか? "); r = scanf("%d", &i); // rは読んだ文字数 } while (r != 1 || i < 1 || i > 3 || a[i] == 0); do { printf("何個とりますか? "); r = scanf("%d", &n); } while (r != 1 || n <= 0 || n > a[i]); a[i] -= n; } } if (my_turn) printf("あなたの勝ちです!\n"); else printf("私の勝ちです!\n"); }
1 番の山の石の数? 5 2 番の山の石の数? 3 3 番の山の石の数? 2 1 ***** 2 *** 3 ** 私の番です. 1 * 2 *** 3 ** 何番の山からとりますか? 2 何個とりますか? 2 1 * 2 * 3 ** 私の番です. 1 * 2 * 3 何番の山からとりますか? 1 何個とりますか? 1 1 2 * 3 私の番です. 1 2 3 私の勝ちです!