经典算法题!!大家帮帮忙

jvg100 2007-06-19 11:56:37
有65颗宝石,两个人来取,规则是每次必须且只能取1-3颗,取完后,手中为偶数颗的取胜,请编制一个先手必胜的取法程序。
解决定结贴!!!
...全文
2589 101 打赏 收藏 转发到动态 举报
写回复
用AI写文章
101 条回复
切换为时间正序
请发表友善的回复…
发表回复
fff3365 2011-12-07
  • 打赏
  • 举报
回复
上帝因为我的骄傲狠狠打了我一个耳光,
结论是对的,不过n=9的转化不是这样的
n = 9 (1)若先手取2,则转化为B为先手,n = 7,所以A败;(2)若先手取1,则后手取1,转化为A为先手,n=7,但此时手中是奇数,会反转原先n=7时的结果,所以A败;(3)先手取3,后手取3,道理同2[Quote=引用 102 楼 fff3365 的回复:]
假设A为先手,B为后手
n = 1 先手必胜,显然
n = 3 先手必胜,显然
n = 5 先手必败,转化方法:(1)若先手取1,后手取3;(2)若先手取2,则转化为B为先手,n=3;(3)先手取3,后手取1
n = 7 先手必胜,先手取2,则转化为B为先手n=5,A必胜
n = 9 先手必败,先手去x,后手取4-x,转化为A为先手,n=5,A必败
...
得出结论n=3 || n ……
[/Quote]
fff3365 2011-12-07
  • 打赏
  • 举报
回复
假设A为先手,B为后手
n = 1 先手必胜,显然
n = 3 先手必胜,显然
n = 5 先手必败,转化方法:(1)若先手取1,后手取3;(2)若先手取2,则转化为B为先手,n=3;(3)先手取3,后手取1
n = 7 先手必胜,先手取2,则转化为B为先手n=5,A必胜
n = 9 先手必败,先手去x,后手取4-x,转化为A为先手,n=5,A必败
...
得出结论n=3 || n = 4*k+1 (k>=0)先手必胜
n = 4*k+3 (k>1)先手必败
楼主困扰你四年的问题终于解决了吧,你这个从不结贴的家伙,败人品,鄙视
syai 2011-12-02
  • 打赏
  • 举报
回复
总数是个奇数
n 是还剩下的数目
首先有下面情况:
归纳法:
n = 2,3 谁先谁胜
n = 4 是手里是奇数是先手必胜,手里是偶数时先手必输
n = 5 是手里剩偶数时先手必胜 手里是奇数先手必输

n = 6,7谁先谁胜
n = 8 是手里剩偶数时先手必胜 手里是奇数先手必输
n = 9 是手里是奇数是先手必胜,手里是偶数时先手必输


n = 4*(2*m) 是手里剩偶数时先手必胜 手里是奇数先手必输
n = 8*(2*m)+1是手里是奇数是先手必胜,手里是偶数时先手必输
n = 4*(2*m+1)是手里是奇数是先手必胜,手里是偶数时先手必输
n = 8*(2*m+1)+1 是手里剩偶数时先手必胜 手里是奇数先手必输

证明用归纳法,太长了,就不贴了
  • 打赏
  • 举报
回复
zgg这个是对的。

因为这个题目是比奇偶,所以总数需要时奇数个,否则,如果总数为偶数,两个人同时为偶数或者同时为奇数,没法分胜负。

基于这个总数为奇数这个前提,可以通过剩下的和自己手中的奇偶性,推断出对方的奇偶性。

所以可以推断出下表(数字为有必赢取法,X表示必输),三列分别表示当前剩余数,你手中为奇数时取法,你手中为偶数时取法。

剩 奇 偶
1 1 X
2 1 2
3 3 2
4 3 X
5 X 1
6 2 1
7 2 3
8 X 3
9 1 X
10 1 2
11 3 2
12 3 X
13 X 1
14 2 1
15 2 3
16 X 3
……

可以看出是以8个为一循环。


[Quote=引用 41 楼 zgg___ 的回复:]

手中为偶数颗为胜,呵呵,差点没有看到耶。
我的答案是:
1、当桌上宝石数除以4余2或3时,如果轮到我,我就一定赢了;
2、当桌上宝石数除以8余0或5时,如果轮到我,如果我手里的宝石数是偶数个,我就一定赢了,如果这时我手里的宝石数是奇数个,那么敌人存在必胜的方法,就是说敌人玩得好,我就必败了。
3、当桌上宝石数除以8余1或4时,如果轮到我,情况刚好和上面的2相反,如果我手里的宝石数是奇数个……
[/Quote]
syai 2011-12-02
  • 打赏
  • 举报
回复
汗,2007年的帖子
syai 2011-12-02
  • 打赏
  • 举报
回复
错啦,
n = 6,7谁先谁胜
n = 8 是手里剩偶数时先手必胜 手里是奇数先手必输
n = 9 是手里是奇数是先手必胜,手里剩偶数时先手必输
以此递推可得
是 n = m*4+2或4*m+3 谁先谁胜
n = m*4 是手里剩偶数时先手必胜 手里是奇数先手必输(只能是取三 就是 n = 4*m+1的情况 )
n = m*4+1是手里是奇数是先手必胜,手里剩偶数时先手必输(当你取一时 自己变偶数,而对方实际是奇数 就是n = m*4的情况)
所以 65 = 4*16+1 手里是偶数 必输
syai 2011-12-02
  • 打赏
  • 举报
回复
这帖子咋还在啊!
唉,。。。。
当n = 3*n+1和3*n+2时先手必胜
低头思蚊香 2011-12-01
  • 打赏
  • 举报
回复

先编个遍历所有情况的程序:

B取1……
A取1——B取2……
B取3……
65- A取2——……

A取3——……

找出一定会使A取胜的路径,再编程让A按照这个路经取值,使游戏按照A取胜的路径进行
chhch11111 2011-09-29
  • 打赏
  • 举报
回复
貌似确实无解,如果说必胜条件改为拿最后一次的人获胜的话倒是有解
hl_md_wj 2011-09-27
  • 打赏
  • 举报
回复
[Quote=引用 71 楼 hl_md_wj 的回复:]
余数 持单 持双
0 F W
1 W W
2 W W
3 W W
4 W F
..............................
这个表的意义如下,第一列表示现在还有多少宝石没有取走,第二列表示在这种状态下,如果先取者手中是单数的情况,第三列表示先取者手中是双数的情况(W表示赢,F表示输),前三行比较好理解,我主要从第四行开始解释我的方法
第四行,如……
[/Quote]

int _tmain(int argc, _TCHAR* argv[])
{
int i;
char p[66][2] ;
p[0][0] = 'F', p[0][1] = 'W';
p[1][0] = 'W', p[1][1] = 'W';
p[2][0] = 'F', p[2][1] = 'W';
for(i = 3; i < 66; i++)
{
if(i % 2 != 0 )
{
if(p[i-1][0] == 'F' || p[i-2][0] == 'F' || p[i-3][0] == 'F')
p[i][0] = 'W';
else
p[i][0] = 'F';
if(p[i-1][1] == 'F' || p[i-2][1] == 'F' || p[i-3][1] == 'F')
p[i][1] = 'W';
else
p[i][1] = 'F';
}
else
{
if(p[i-1][1] == 'F' || p[i-2][1] == 'F' || p[i-3][1] == 'F')
p[i][0] = 'W';
else
p[i][0] = 'F';
if(p[i-1][0] == 'F' || p[i-2][0] == 'F' || p[i-3][0] == 'F')
p[i][1] = 'W';
else
p[i][1] = 'F';
}
}
printf("余数 持单 持双\n");
for(i = 0; i < 66; i++)
printf("%4d %4c %4c\n",i,p[i][0],p[i][1]);
return 0;
}
余数 持单 持双
0 F W
1 W W
2 F W
3 W F
4 W W
5 W W
6 W F
7 F W
8 W W
9 W W
10 F W
11 W F
12 W W
13 W W
14 W F
15 F W
16 W W
17 W W
18 F W
19 W F
20 W W
21 W W
22 W F
23 F W
24 W W
25 W W
26 F W
27 W F
28 W W
29 W W
30 W F
31 F W
32 W W
33 W W
34 F W
35 W F
36 W W
37 W W
38 W F
39 F W
40 W W
41 W W
42 F W
43 W F
44 W W
45 W W
46 W F
47 F W
48 W W
49 W W
50 F W
51 W F
52 W W
53 W W
54 W F
55 F W
56 W W
57 W W
58 F W
59 W F
60 W W
61 W W
62 W F
63 F W
64 W W
65 W W
上次写错了一个数,这次修正,先手必胜,因为先手持双开始(0),只要拿走3个,后手方必持双从62个开始取,上表中可以看出他是必败的,这次应该是对的了
hl_md_wj 2011-09-22
  • 打赏
  • 举报
回复
[Quote=引用 71 楼 hl_md_wj 的回复:]
余数 持单 持双
0 F W
1 W F
2 W W
3 W W
4 W F
..............................
这个表的意义如下,第一列表示现在还有多少宝石没有取走,第二列表示在这种状态下,如果先取者手中是单数的情况,第三列表示先取者手中是双数的情况(W表示赢,F表示输),前三行比较好理解,我主要从第四行开始解释我的方法
第四行,如……
[/Quote]

我根据我回复的方法写了个程序,下面是程序和运行结果
int _tmain(int argc, _TCHAR* argv[])
{
int i;
char p[66][2] ;
p[0][0] = 'F', p[0][1] = 'W';
p[1][0] = 'W', p[1][1] = 'F';
p[2][0] = 'W', p[2][1] = 'W';
for(i = 3; i < 66; i++)
{
if(i % 2 != 0 )
{
if(p[i-1][0] == 'F' || p[i-2][0] == 'F' || p[i-3][0] == 'F')
p[i][0] = 'W';
else
p[i][0] = 'F';
if(p[i-1][1] == 'F' || p[i-2][1] == 'F' || p[i-3][1] == 'F')
p[i][1] = 'W';
else
p[i][1] = 'F';
}
else
{
if(p[i-1][1] == 'F' || p[i-2][1] == 'F' || p[i-3][1] == 'F')
p[i][0] = 'W';
else
p[i][0] = 'F';
if(p[i-1][0] == 'F' || p[i-2][0] == 'F' || p[i-3][0] == 'F')
p[i][1] = 'W';
else
p[i][1] = 'F';
}
}
printf("余数 持单 持双\n");
for(i = 0; i < 66; i++)
printf("%4d %4c %4c\n",i,p[i][0],p[i][1]);
return 0;
}
余数 持单 持双
0 F W
1 W F
2 W W
3 W W
4 W F
5 F W
6 W W
7 W W
8 F W
9 W F
10 W W
11 W W
12 W F
13 F W
14 W W
15 W W
16 F W
17 W F
18 W W
19 W W
20 W F
21 F W
22 W W
23 W W
24 F W
25 W F
26 W W
27 W W
28 W F
29 F W
30 W W
31 W W
32 F W
33 W F
34 W W
35 W W
36 W F
37 F W
38 W W
39 W W
40 F W
41 W F
42 W W
43 W W
44 W F
45 F W
46 W W
47 W W
48 F W
49 W F
50 W W
51 W W
52 W F
53 F W
54 W W
55 W W
56 F W
57 W F
58 W W
59 W W
60 W F
61 F W
62 W W
63 W W
64 F W
65 W F
结论,先手必败 请高手看看有没有问题
aliasy 2011-09-16
  • 打赏
  • 举报
回复
先手必败,先手必败,先手必败,先手必败,先手必败,先手必败,先手必败,先手必败,先手必败,先手必败,先手必败,先手必败,先手必败,先手必败,先手必败,先手必败,先手必败,先手必败,先手必败,先手必败,先手必败,先手必败,先手必败,先手必败,先手必败,先手必败,先手必败,先手必败,先手必败,先手必败,先手必败,先手必败,先手必败。4*16=64。
支持英文数字 2011-09-16
  • 打赏
  • 举报
回复
学习了。
yyfhz 2011-09-15
  • 打赏
  • 举报
回复
杯具了,上面说的不对,实际上F(4)应该为False才是。。。要么改成这个样子试试看:
定义F(x)=true表示有x个球,先取者手上能有偶数个球的情况
定义F(x)=false表示有x个球,先取者手上只能有奇数个球的情况
定义G(x)=true表示有x个球,后取者手上能有偶数个球的情况
定义G(x)=false表示有x个球,后取者手上只能有奇数个球的情况
则有
F(2k)=G(2k)
F(2k+1)=Not G(2k+1)
以及
F(1)= false ==> G(1)=true
F(2)= true ==> G(2)=true
F(3)= true ==> G(3)=false
对于F(x>3)的情况,有
F(2k)= (G(2k-1)) or (G(2k-2)) or (G(2k-3))
= (Not F(2k-1)) or (F(2k-2)) or (Not F(2k-3))
F(2k+1) = (Not G(2k)) or (Not G(2k-1)) or (Not G(2k-2))
= F(2k-1) or (Not F(2k-2)) or F(2k-3)
照这个样子去算算看吧
低头思蚊香 2011-09-14
  • 打赏
  • 举报
回复
决定最终胜利的最后情况有种:
最后一轮,只有1个,先手输;
最后一轮,有2个,先手取1个,后手输;
最后一轮,有3个,先手取2个,后手输;
最后一轮,有4个,先手取3个,后手输;
最后二轮,有5个,先手取1个,变4,先手输;
最后二轮,有5个,先手取2个,变3,先手输;
最后二轮,有5个,先手取3个,变2,先手输;
最后二轮,有6个,先手取1个,变5,有6个最后三轮;……好难,不会,mark
yyfhz 2011-09-14
  • 打赏
  • 举报
回复
把目标集中在“先取者手上有偶数个算胜利,否则算失败”,
并将题目改写成为“有球若干,先取者手上若能有偶数个球则算胜利,否则算失败”。
定义函数F(x)=true表示有x个球,先取者手上能有偶数个球的情况,F(x)=false表示有x个球,先取者手上无法获得偶数个球的情况。

则显然有F(2k)=true。而对x=2k+1的情形,则有
F(1)=false (先取者输)
F(3)=(Not F(2)) or (Not F(1)) = true
F(5)=(Not F(4)) or (Not F(3)) or (Not F(2)) = False
F(7)=(Not F(6)) or (Not F(5)) or (Not F(4)) = true
一般的,有
F(2k+1)=(Not F(2k)) or (Not F(2k-1)) or (Not F(2k-2)) --即先手可取1, 2, 或3,而后手方只能成为取2k, 2k-1或2k-2这3种可能情况下的先手者,只有在这3种情况下均获胜,才能说F(2k+1)=False。

由于F(2k)始终=true,因此若有F(2k+1)=true,则F(2k), F(2k+1), F(2k+2)均为True,因此只能F(2k+3)为False,表示在此种情况下先手方必败(除非后手方失误)。
若F(2k+1)=false,则F(2k+3)必为true,表示先手方必胜。
F(1), F(3), F(5), F(7)... 的值为false, true, false, true,...看一下可以发现其规律为
F(4k+1)=false以及F(4k+3)=true。 ==>看来LZ的65个先手方是无法取胜的喽。

而F(4k+3)成功的唯一途径就是先手者取2颗,然后把这个4k+1这个烂摊子扔给对手。

而对于F(4k+1)来说,先手方要么取1或3颗,这样一来剩下的数量就变成了偶数,对方只要先取2个,然后视先手方
取的数量的奇偶性取相同奇偶性的个数即可轻易获胜;
要么先手方取2个,然后后手方也取2个,又把4k+1的烂摊子扔回给先手方。

所以,对于双方来讲,最好的办法就是每人个取两个,胜负各按天命。
超级大笨狼 2011-09-13
  • 打赏
  • 举报
回复
好玩,mark一下,以后慢慢研究.
hl_md_wj 2011-09-13
  • 打赏
  • 举报
回复
[Quote=引用 84 楼 love_ubuntu 的回复:]
第一个人拿n颗 , 第二个人拿 4-n 颗, 这样以来, 16次后, 只剩下1颗,而这一颗一定是第一个人拿,所以第一个人不管是怎么样拿, 都是输的, 因为他拿到了奇数个。
[/Quote]

16次后,第一个人手中一定是偶吗,为什么?
Jokul_Lee 2011-09-13
  • 打赏
  • 举报
回复
[Quote=引用 86 楼 superdullwolf 的回复:]

好玩,mark一下,以后慢慢研究.
[/Quote]有天晚上,躺在床上想这个问题,都没睡着觉
不争聊技术 2011-09-11
  • 打赏
  • 举报
回复
第一个人拿n颗 , 第二个人拿 4-n 颗, 这样以来, 16次后, 只剩下1颗,而这一颗一定是第一个人拿,所以第一个人不管是怎么样拿, 都是输的, 因为他拿到了奇数个。
加载更多回复(81)

33,010

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧