所在位置:主页 > 程序语言 > 谁拿最后一根火柴 程序设计 大家帮帮忙!

谁拿最后一根火柴 程序设计 大家帮帮忙!

发布时间:2023-12-23 09:39来源:www.sf1369.com作者:宇宇

这个道理和编程无关,每人最多取4根,

1+4=5

21=5*4+1

也就是说,只要保证每轮两方之和是5,那么4轮后取走20根,最后先取的人必定取最后一根。

第二题:需要用递推的方式,计算所有必胜必输的状态,然后保证每次取火柴都让对方到达必输状态。

所谓必输就是只剩最后一根,或者无论怎么取后的结果都是必胜。

所谓必胜,就是可以对方到达必输状态的情况。

程序如下:

import java.io.*;

public class Picker {

// 火柴堆的输赢状况

private final static int EMPTY=0; // 这种排列不可能出现,如108

private final static int UNKNOWN=1; // 尚未计算出

private final static int WIN=2; //必胜

private final static int LOSE=3; //必输(如果对方够聪明)

// 用数组,保存每种火柴堆排列的输赢状态,下标为排列,如357, 111, 001, 100等等

private int[] status;

public Picker() {

// 初始化状态数组,排除所有不可能出现的情况

status = new int[358]; // 0 - 357

int i,j,k;

for (i=0; i<=3; i++) {

for (j=0; j<=5; j++) {

for (k=0; k<=7; k++) {

status[i*100+j*10+k] = UNKNOWN;

}

}

}

// 已知 100, 010, 001必输

status[1]=LOSE;

status[10]=LOSE;

status[100]=LOSE;

// 所有能使对方到达上述三个状态的排列都是必赢的

markWin(1);

markWin(10);

markWin(100);

// 递推计算,直至357的情况被计算出来

while (status[357] == UNKNOWN) {

//找到第一个没有计算的

int node=2;

for (node = 2; node<357; node++) {

if (status[node] == UNKNOWN) break;

}

// 它的所有下个状态肯定都是必赢,不然以前就能算出。

status[node] = LOSE;

// 所有能使对方到达这个状态的排列都是必赢的

markWin(node);

}

}

// 所有能使下个状态变必输的排列都是必赢的

private void markWin(int node) {

// 假设node为必输

// 每堆的数量分别为i,j,k

int i = node / 100;

int j = node / 10 % 10;

int k = node % 10;

// 先是第一堆,可能为i+1, i+2, ..., 3

for (int i1 = i+1; i1 <= 3; i1++) {

status[i1*100+j*10+k] = WIN;

}

// 第二堆

for (int j1 = j+1; j1 <= 5; j1++) {

status[i*100+j1*10+k] = WIN;

}

// 第三堆

for (int k1 = k+1; k1 <= 7; k1++) {

status[i*100+j*10+k1] = WIN;

}

}

// 查找所有可能的一次取火柴后的排列,找出其中必输的状态,把这个作为自己的走法

public int getWinPick(int node) {

//每堆的数量分别为i,j,k

int i = node / 100;

int j = node / 10 % 10;

int k = node % 10;

// 先是第一堆,可能留下0, 1, ..., i-1

for (int i1 = 0; i1 < i; i1++) {

if (status[i1*100+j*10+k]==LOSE) return i1*100+j*10+k;

}

// 第二堆

for (int j1 = 0; j1 < j; j1++) {

if (status[i*100+j1*10+k]==LOSE) return i*100+j1*10+k;

}

// 第三堆

for (int k1 = 0; k1 < k; k1++) {

if (status[i*100+j*10+k1]==LOSE) return i*100+j*10+k1;

}

// 没有找到,那么先顽强抵抗一下,只取一根

if (i>0) return (i-1)*100+j*10+k;

else if (j>0) return (j-1)*10+k;

else return k-1;

}

public static void main(String[] args) throws Exception {

Picker picker = new Picker();

// 一开始的排列是357

int node = 357;

BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));

while (node > 0) {

// 计算机先

System.out.print(Now is +node);

node = picker.getWinPick(node);

System.out.println(, I pick to +node);

if (node == 0) {

System.out.println(I lose);

return;

}

// 对方再取

System.out.println(Now is your turn: );

String input = stdin.readLine();

int node1 = 0;

try {

node1 = Integer.parseInt(input);

} catch (Exception e) {

System.out.println(Invalid input, you lose);

break;

}

// 这里没有判断取的是否合法,即node和node1之间是否仅差一位数字

if ( node1==0 ) {

System.out.println(You lose);

}

node = node1;

}

}

}

这个程序只是例子,是说明算法,没有判断输入的合法性,所以不能一直输入2的,人嘛,自己也遵循一下游戏规则吧。

另外,稍做改动,如果不利,计算机不会马上认输了。