C语言的取石头游戏,----超高难度的算法题

Isabel_y 2007-05-26 09:31:03
C语言的取石头游戏,----超高难度的算法题


有甲乙两个人玩取石子游戏,共有n个石子(1<=n<=30000)两个人轮流取,甲先取.每次最多取m个(1<=m<=30000)最少取一个,当轮到谁取的时候没有石子了,谁就赢.
比如4个石子,每次最多取3个,那末先取的人(甲)一定赢n和m谁大没有限制.)
(甲拿走3个,乙只拿走1个,下面轮到甲了,但是没有石子了,甲赢了.)
 现在要求你写一个程序,输入n(总的石子个数),最多可以取的石子个数m,输出甲(先取的人)是否会赢,会赢的话输出YES,否则输出LOSE.
 我们这里假设甲乙两个人都采取最好的策略,也就是甲乙都非常想赢而且足够聪明.
 比如输入4 3 输出YES

请教高手
...全文
1326 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
expter 2007-06-02
  • 打赏
  • 举报
回复
都这么强啊
shu_yoyo 2007-06-02
  • 打赏
  • 举报
回复
mark
WinWing 2007-05-30
  • 打赏
  • 举报
回复
汗楼上的.

什么事情都由电脑做了,那还要人来干吗?
夜雨_倚琴 2007-05-30
  • 打赏
  • 举报
回复
上面的算法分析的的确很有道理.
不过这个是编程题,不是数学分析,对于这样的题目随便找本数模的书都可以翻到.

不过我觉得问题在于编程.
什么事情都由人做了,那电脑还干什么.
葫芦鬼 2007-05-28
  • 打赏
  • 举报
回复
mark
kyorihe 2007-05-27
  • 打赏
  • 举报
回复
这个猛!弓虽!
laizhenyuan 2007-05-27
  • 打赏
  • 举报
回复
呵呵,如果分析的好,算法其实很简单
首先我们可以将n和m的关系分为以下3种(n,m无论是谁大都可以用以下3种方式表示),
(1)n=(m+1)*a (a>0)
(2)n=(m+1)*a+1 (a>=0)
(3)n=(m+1)*a+b (a>=0,m+1>b>1)
先分析第2种情况,在这种情况下,甲是一定会输的,因为假设甲先取x个,乙就可以取y个使得x+y=m+1,这样下去,甲最后取的时候一定是只有一个,这样甲必输;
第1和第3种情况甲先取,甲是必胜的,对于第1种情况,甲第一次取m个,对于第3种情况,甲第一次取b-1个,在这两种情况下,甲取玩第一次后,对于乙来说都是变成了第二种情况,因此甲必胜;
分析至此,算法应该比较明朗了,我们只需判断n,m的关系属于第几种就可得出结果了。代码我就不写了。
kyorihe 2007-05-27
  • 打赏
  • 举报
回复
n=100,m=98时应该返回LOSE吧,可是LS返回YES噢,我的代码:

#include<stdio.h>

#define MAXN 30000
int a[MAXN+1];

int DPfun(int n,int m)
{
int i,k;
if(n==1)
return false;
else if( m>=(n-1) )
return true;
else{
a[1]=0;
for(i=2;i<=(m+1);i++)
a[i]=1;
for(i=(m+2); i<=n; i++)
{
for(k=1;k<=m && a[i-k];k++);
if(k>m)
a[i]=0;
else
a[i]=1;
}
return a[n];
}
}

int main()
{
int n,m;
scanf("%d %d", &n,&m);
if(DPfun(n,m))
printf("YES\n");
else
printf("LOSE\n");

return 0;
}
kyorihe 2007-05-27
  • 打赏
  • 举报
回复 1
to fflush: 不好意思,是我弄错了^_^
忘了将S[4]改成S[100]
WinWing 2007-05-27
  • 打赏
  • 举报
回复
赞laizhenyuan() ,佩服
fflush 2007-05-27
  • 打赏
  • 举报
回复
那你就运行一下kyorihe() 的吧
Isabel_y 2007-05-27
  • 打赏
  • 举报
回复
我运行了一下fflush的,怎么有错误啊?我找不明白>?
Isabel_y 2007-05-27
  • 打赏
  • 举报
回复
都这么厉害啊~~
好羡慕啊!
我不仅编不出这样的程序,而且我还没看懂呢?
太郁闷了~~
就学了1年C语言! 这才看到自己能算什么啊~~~
fflush 2007-05-27
  • 打赏
  • 举报
回复
to kyorihe: 我的在n=100,m=98的时候也是返回lose,你可能忘了将S[4]改成S[100]

laizhenyuan的方法很好,赞一个:)
fengdream 2007-05-27
  • 打赏
  • 举报
回复
mark之。。。
fflush 2007-05-26
  • 打赏
  • 举报
回复
可以这么做,假设f(n,m)计算出在有n个石子,每次可以取[1,m]个的情况下,先取的人是否一定可以赢。如果f(n,m)返回真,那么意味着存在一个方案,使得先取的人取t个并且f(n-t,m)为假。因此可以这样计算f
bool f(int n, int m)
{
int i = (n - m > 0 ? n - m : 1);

while (i < n && f(i, m))
i++;

return i == n ? false : true;
}
这个算法的复杂度很高,采用迭代的方式可以获得线性的复杂度,代码如下
#include <stdio.h>
#include <stdlib.h>

int S[30001] = {-1}; //每一个S[i]相当于f(i, m),这里忽略了S[0]

void stone (int n, int m)
{
int lose = 1;

S[1] = 0;
for (int i = 2; i <= n; i++)
{
S[i] = (lose ? 1 : 0);

if (i - m > 0 && S[i - m] == 0)
--lose;

if (S[i] == 0)
++lose;
}
}

int main ()
{
stone (4, 3);

printf ("%s", (S[4] == 1 ? "YES" : "LOSE"));

system ("pause");
}

69,382

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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