求解Grundy算法(在线等待)

hxzb7215191 2005-03-28 01:14:30
例1:如果桌上有10个数,规定甲乙两人轮流取子。每次只准取1、2或5个子。
首先令g(0)=0,那么
1.如果还剩下1颗子,可以取1个,则变为只有0个子,而g(0)=0,
  所以g(1)=1;
2.如果还剩下2颗子,a.可以取1个,则变为只有1个子,而g(1)=1,
           b.可以取2个,则变为只有0个子,而g(0)=0,
所以g(2)=2;
3.如果还剩下3颗子,a.可以取1个,则变为只有2个子,而g(2)=2,
           b.可以取2个,则变为只有1个子,而g(1)=1,
所以g(3)=0;
4.如果还剩下4颗子,a.可以取1个,则变为只有3个子,而g(3)=0,
           b.可以取2个,则变为只有2个子,而g(2)=2,
所以g(4)=1;
5.如果还剩下5颗子,a.可以取1个,则变为只有4个子,而g(4)=1,
           b.可以取2个,则变为只有3个子,而g(3)=0,
           c.可以取5个,则变为只有0个子,而g(0)=0,
所以g(5)=2;
6.如果还剩下6颗子,a.可以取1个,则变为只有5个子,而g(5)=2,
           b.可以取2个,则变为只有4个子,而g(4)=1,
           c.可以取5个,则变为只有1个子,而g(1)=1,
所以g(6)=0;
......

以此类推得出:
  X = 0  1  2  3  4  5  6  7  8  9  10
g(X)= 0  1  2  0  1  2  0  1  2  0   1
如果还剩10个棋子,那么先取的一定获胜。

我要写出一这样的函数int g(int param)
来得到对应的数值。
有哪位高人能写出来。
100分送上。
...全文
79 7 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
bobob 2005-03-31
  • 打赏
  • 举报
回复
超过40就很慢了!呵呵
我再改进一下
bobob 2005-03-31
  • 打赏
  • 举报
回复
#include <iostream.h>

#include <iostream.h>

int g(const int);

int main()
{
int i;
cout<<"please input num:";
cin>>i;
cout<<"g("<<i<<")="<<g(i)<<endl;

return 0;

}

int g(const int num)
{
if(num == 0)
{
return 0;
}
if(num == 1)
{
return 1;
}
if(num == 2)
{
return 2;
}
if(num == 3)
{
return 0;
}
if(num == 4)
{
return 1;
}
if(num>=5)
{
int num1 ,num2,num3;
num1 = g(num-1);
num2 = g(num-2);
num3 = g(num-5);
if(num1!=0 && num2!=0 && num3!=0)
{//没有一个等于0,返回0
return 0;
}
if(num1!=1 && num2!=1 && num3!=1)
{//有一个等于0,没有一个等于1,返回1
return 1;
}
if(num1!=2 && num2!=2 && num3!=2)
{//有一个等于0,一个等于1,没有一个等于2,返回2
return 2;
}

return 3;
}
else
return -1;
}
hxzb7215191 2005-03-29
  • 打赏
  • 举报
回复
请大家帮忙啊。。。
hxzb7215191 2005-03-28
  • 打赏
  • 举报
回复
游戏规则要实现两种:
两堆棋子情形:你和电脑轮流取子。由电脑决定谁先取子,每人每次可以在其中一堆取任意个(但至少取一个),或者在两堆取同样多个。最后一定是电脑使棋子数变为0而获胜。
多堆棋子情形:桌上有若干种颜色的棋子,每种均有两堆。你和电脑轮流取子,由电脑决定谁先取子,每人每次可以在其中一堆取任意个(但至少取一个),或者在同色的两堆中取相同多棋子。最后一定是电脑使棋子数变为0则获胜。
注意:每堆棋子个数随机生成。
要求一共有以下几个模块:
输入模块:问用户是玩两堆还是多堆 。
显示模块:显示有多少棋子;是电脑先取,还是你先取计算Grundy函计算Grundy函数值模块:显示函数值(该模块是我这个设计的核心)
计算机取子模块:电脑每次取多少,并监督其取子的合法性
用户取子模块:用户每次取多少,并监督其取子的合法性
显示模块: 显示每次取子之后,棋子的状态




下面是Grundy函数方法:(就是求以下的这个g(x))
定义:设局势X经过一切可能的合法动作,可以分别变为局势Y1、Y2…Yk(称为X的后继),则g(x)定义为最小的没有赋给任一后继的非负整数。

以下只是一个Grundy函数的最简单例子:

例1:如果桌上有10个数,规定甲乙两人轮流取子。每次只准取1、2或5个子。
首先令g(0)=0,那么
1.如果还剩下1颗子,可以取1个,则变为只有0个子,而g(0)=0,
  所以g(1)=1;
2.如果还剩下2颗子,a.可以取1个,则变为只有1个子,而g(1)=1,
           b.可以取2个,则变为只有0个子,而g(0)=0,
所以g(2)=2;
3.如果还剩下3颗子,a.可以取1个,则变为只有2个子,而g(2)=2,
           b.可以取2个,则变为只有1个子,而g(1)=1,
所以g(3)=0;
4.如果还剩下4颗子,a.可以取1个,则变为只有3个子,而g(3)=0,
           b.可以取2个,则变为只有2个子,而g(2)=2,
所以g(4)=1;
5.如果还剩下5颗子,a.可以取1个,则变为只有4个子,而g(4)=1,
           b.可以取2个,则变为只有3个子,而g(3)=0,
           c.可以取5个,则变为只有0个子,而g(0)=0,
所以g(5)=2;
6.如果还剩下6颗子,a.可以取1个,则变为只有5个子,而g(5)=2,
           b.可以取2个,则变为只有4个子,而g(4)=1,
           c.可以取5个,则变为只有1个子,而g(1)=1,
所以g(6)=0;
......

以此类推得出:
  X = 0  1  2  3  4  5  6  7  8  9  10
g(X)= 0  1  2  0  1  2  0  1  2  0   1
如果还剩10个棋子,那么先取的一定获胜。


结论:
1. 若g(x)>0, 则存在一个合法动作使 x 的后继 y 有g(y)=0;
2. 若g(x)=0,则对 x 的任一后继 y 都有g(y)〉0
若g(x)〉0,则先动作者,有获胜策略
若g(x)=0,则后动作者,有获胜策略

我的游戏的Grundy函数大致如下:
两堆情形:局势X=(m,n),因为没考虑颜色,所以g(m,n)= g(n,m),假设m<=n. 设g(0,0)=0,
1. g(0,1)=1,因为可以取1个,变为局势(0,0),而g(0,0)=0;
2. g(0,2)=2,因为可以取1个,变为局势(0,1),而g(0,1)=1,
可以取2个,变为局势(0,0),而g(0,0)=0;
2. g(0,3)=2,因为可以取1个,变为局势(0,2),而g(0,2)=2,
可以取2个,变为局势(0,1),而g(0,1)=1,
可以取3个,变为局势(0,0),而g(0,0)=0;
......
g(0,n)=n
两堆都还有棋子时:
1. g(1,1)=2,
在第1堆中取1个,变为局势(0,1),g(0,1)=g(1,0),而g(0,1)=1,
在第2堆中取1个,变为局势(1,0),而g(1,0)=1,
在2堆中都分别取1个,变为局势(0,0),而g(0,0)=0,

2. g(1,2)=0
因为在第1堆中取1个,变为局势(0,2),g(0,2)=2,
在第2堆中取2个,变为局势(1,0),g(0,1)=g(1,0),g(1,0)=1,
在第2堆中取1个,变为局势(1,1),g(1,1)=2,
在第1堆中取1个,在第2堆中取1个,变为局势(0,1),g(0,1)=1
......

你可以设一个数组flag[N],初始化设:flag[0]= flag[1]=…= flag[N]=0
一旦有某个g值=k时,令flag[k]=1

hxzb7215191 2005-03-28
  • 打赏
  • 举报
回复
帮忙啊。

我看了半天没有看来这个规律的。

请大虾们给点思想吧。
goodheartppl 2005-03-28
  • 打赏
  • 举报
回复
UP
Algorithms   本次README修订为算法仓库Algorithms的第100次commit,首先我们庆祝自2016年8月4日本仓库建立以来Dev-XYS在算法学习方面取得的显著进步!   这里有各种算法的C++代码,任何人可以在自己的任何程序中使用,欢迎大家指出代码中的错误以及有待改进的地方。   本仓库内所有代码的授权方式为Unlicense,大家如果使用我的代码开发自己的软件挣了大钱,或是参考我的代码在NOI中得了金牌,我都会很高兴的。使用这里的代码之后,你可以自主选择是否公开源代码。总而言之,你可以把这里的代码当作你自己写的一样,无论怎样使用都是被允许的。但是,我不对本仓库内代码的正确性负责。大家要是使用我的代码开发软件而导致程序崩溃,或是参考我的代码在考试时出错,请不要向我抱怨。如果你愿意,遇到问题可以在Issues中提出来,我们共同解决。我们不赞成Pull Request,因为本仓库主要储存作者已经学习的算法,全部代码均由作者本人负责维护与更新。   以下索引提供了本仓库内算法的中文名,方便大家查找。更新可能有很长时间的延迟,不保证所有算法的名称都在列表中出现。 Index --------------------------Contents-------------------------- --------------------------FileName-------------------------- AC自动机 Aho-Corasick-Automation 单源最短路径(SPFA) Bellman-Ford(Queue-Optimised) 单源最短路径(Bellman-Ford) Bellman-Ford 使用Edmonds-Karp进行二分图匹配 Bigrpah-Matching(Edmonds-Karp) 普通的二叉搜索树 Binary-Search-Tree 广度优先搜索 Breadth-First-Search 冒泡排序 Bubble-Sort 桶排序 Bucket-Sort 组合数的递推求解 Combination(Recursion) 枚举组合 Combination 基本的复数类 Complex-Number 割点 Cut-Vertex 深度优先搜索 Depth-First-Search 堆优化的Dijkstra算法 Dijkstra(Heap-Optimised) 并查集 Disjoint-Set-Union 最大流Edmonds-Karp算法 Edmonds-Karp 欧拉函数 Euler's-Totient-Function 有向图的欧拉回路 Eulerian-Tour(Digraph) 拓展欧几里得算法 Extended-Euclid 简单的快速幂 Fast-Exponentiation 树状数组 Fenwick-Tree 所有结点对之间的最短路径(Floyd) Floyd-Warshall 凸包算法(Graham扫描法) Graham-Scan 辗转相除法求最大公约数 Greatest-Common-Divisor 堆排序 Heap-Sort ISAP算法 Improved-Shortest-Augmenting-Path(Naive) 插入排序 Insertion-Sort 字符串匹配(KMP) Knuth-Morris-Pratt 最小生成树(Kruskal) Kruskal 最近公共祖先(Tarjan) Least-Common-Ancestor(Tarjan) 使用后缀数组求解最长公共子串 Longest-Common-Substring 最长上升子序列(n·log(n)) Longest-Increasing-Subsequence(n·log(n)) 倍增法求最近公共祖先 Lowest-Common-Ancestor(Doubling) 朴素的矩阵乘法 Matrix-Multiplication(Naive) 归并排序 Merge-Sort 最小堆 Min-Heap 乘法逆元 Modular-Multiplicative-Inverse 仅支持单点修改的可持久化线段树(维护区间和值) Persistent-Segment-Tree(Sum) 试除法素数测试 Prime-Check(Naive) 线性的素数筛法 Prime-Sieve(Linear) 队列的基本操作 Queue 快速排序的优化版本 Quick-Sort(Extra-Optimised) 快速排序的随机化版本 Quick-Sort(Randomized) 快速排序 Quick-Sort 使用向量叉积判断两个有向线段的时针关系 Segment-Direction 线段树维护区间最大值 Segment-Tree(Maximum) 线段树维护区间最小值 Segment-Tree(Minimum) 线段树维护区间和值 Segment-Tree(Sum) 普通的选择算法 Selection Eratosthenes素数筛法 Sieve-of-Erotosthenes 指针版的单向链表 Singly-Linked-List(Pointer) 跳表 Skip-List ST表 Sparse-Table 伸展树 Splay 博弈论SG函数 Sprague-Grundy 栈的基本操作 Stack 递推法求解无符号第一类斯特林数 Stirling-Number(Cycle,Unsigned,Recursion) 递推法求解第二类斯特林数 Stirling-Number(Subset,Recursion) 倍增法求解后缀数组 Suffix-Array(Doubling) 倍增法求解后缀数组(附带Height数组) Suffix-Array-with-Height(Doubling) 使用Tarjan算法求解强连通分量 Tarjan(Strongly-Connected-Components) 数组版的字典树 Trie(Array) 指针版的字典树 Trie(Pointer)

19,472

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 图形处理/算法
社区管理员
  • 图形处理/算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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