石子问题
石子合并问题报告
石子合并(动态规划)详细解题报告2007-02-25 14:58一.试题在一个园形操场的四周摆放N堆石子(N≤100),现要将石子有次序地合并成一堆。
规定每次只能选相邻的两堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。
编一程序,由文件读入堆数N及每堆的石子数(≤20),①选择一种合并石子的方案,使得做N-1次合并,得分的总和最小;②选择一种合并石子的方案,使得做N-1次合并,得分的总和最大。
例如,所示的4堆石子,每堆石子数(从最上面的一堆数起,顺时针数)依次为4594。
则3次合并得分总和最小的方案:8+13+22=43得分最大的方案为:14+18+22=54输入数据:文件名由键盘输入,该文件内容为:第一行为石子堆数N;第二行为每堆的石子数,每两个数之间用一个空格符分隔。
输出数据:输出文件名为output.txt从第1至第N行为得分最小的合并方案。
第N+1行是空行。
从第N+2行到第2N+1行是得分最大合并方案。
每种合并方案用N行表示,其中第i行(1≤i≤N)表示第i 次合并前各堆的石子数(依顺时针次序输出,哪一堆先输出均可)。
要求将待合并的两堆石子数以相应的负数表示,以便标识。
输入输出范例:输入文件内容:44594输出文件内容:-459-4-8-59-13-9224-5-944-14-4-4-1822二.算法分析竞赛中多数选手都不约而同地采用了尽可能逼近目标的贪心法来逐次合并:从最上面的一堆开始,沿顺时针方向排成一个序列。
第一次选得分最小(最大)的相邻两堆合并,形成新的一堆;接下来,在N-1堆中选得分最小(最大)的相邻两堆合并……,依次类推,直至所有石子经N-1次合并后形成一堆。
例如有6堆石子,每堆石子数(从最上面一堆数起,顺时针数)依次为346542要求选择一种合并石子的方案,使得做5次合并,得分的总和最小。
按照贪心法,合并的过程如下:每次合并得分第一次合并346542 ->5第二次合并54654 ->9第三次合并9654 ->9第四次合并969 ->15第五次合并159 ->2424总得分=5+9+9+15+24=62但是当我们仔细琢磨后,可得出另一个合并石子的方案:每次合并得分第一次合并346542 ->7第二次合并76542 ->13第三次合并13542 ->6第四次合并1356 ->11第五次合并1311 ->2424总得分=7+6+11+13+24=61显然,后者比贪心法得出的合并方案更优。
博弈论取石子问题
博弈论取石子问题
博弈论取石子问题是一类经典的博弈问题,也被称为Nim游戏。
这个问题一般描述为:有一堆石子,两名玩家轮流从中取出若干个石子,每次取石子的数量有限制(例如,每次最多只能取1个或者2个),最终取光所有石子的玩家获胜。
在这个问题中,两位玩家都采取最优策略,并且可以假设每位玩家都会尽力阻止对方获胜。
这样,对于每一轮的取石子操作,可以通过数学的方法来判断哪位玩家有必胜策略。
一般来说,博弈论取石子问题可以通过异或运算来求解。
具体思路如下:
1. 通过异或运算计算出所有石子数量的异或和。
2. 如果异或和为0,表示当前状态下无论怎么取石子,都无法保证必胜,此时当前玩家必输。
3. 如果异或和不为0,表示当前状态下存在某种取法,可以保证必胜。
具体的取法是找到最高位上的1,然后将某一堆石子数量减去该最高位1的数量,使得新的异或和为0。
通过上述思路,可以快速计算出哪位玩家具有必胜策略。
当然,如果可以通过编程的方式来模拟和计算,会更加直观和方便。
动态规划-石子合并问题
动态规划-⽯⼦合并问题(1)问题描述 在⼀个圆形操场的四周摆放着 num 堆⽯⼦。
先要将⽯⼦有次序地合并成⼀堆。
规定每次只能选相邻的 2 堆⽯⼦合并成新的⼀堆,并将新的⼀堆⽯⼦数记为该次合并的耗费⼒⽓。
试设计⼀个算法,计算将 n 堆⽯⼦合并成⼀堆的最省⼒⽓数。
(2)算法思想 对于给定的 n 堆⽯⼦,当只有⼀堆时,不⽤搬,进⽽不耗费⼒⽓,然后依次计算出从 2 堆 ~ num 堆⽯⼦的最优解,并且堆数递增求最优解,依赖于上⼀步的解进⾏计算所得;(3)算法思路 此解法和矩阵连乘类似,我们知道矩阵连乘也是每次合并相邻的两个矩阵,那么⽯⼦合并可以⽤矩阵连乘的⽅式来解决。
设 dp[i][j] 表⽰第 i 到第 j 堆⽯⼦合并的最优值,sum[i][j] 表⽰第 i 到第 j 堆⽯⼦的所耗费的⼒⽓总数。
动规⽅程如下:(4)代码展⽰public class StoneMerge {/*** 记录⽯⼦堆的数量*/private static int num;/*** 记录每堆⽯⼦的重量*/private static int[] weight;/*** 记录⽯⼦堆断开的位置【便于计算局部最优解】*/private static int[][] location;/*** 记录⽯⼦堆局部最优解,以⾄于求得最终最优解【动规⽅程】*/private static int[][] dp;/*** 初始化数据*/private static void initData() {Scanner input = new Scanner(System.in);System.out.println("请输⼊⽯⼦堆数量:");num = input.nextInt();weight = new int[num];System.out.println("请输⼊每堆⽯⼦的重量:");for (int i = 0; i < weight.length; i++) {weight[i] = input.nextInt();}// 定义成 int 类型的⼆维数组,创建完每个元素直接初始化为 0dp = new int[num][num];location = new int[num][num];}/*** 计算最省最费⼒⽓值*/private static void dpFindMinStrength() {// 初始化 dp 数组for (int m = 0; m < num; m++) {dp[m][m] = 0; // ⼀堆⽯⼦,不⽤搬,耗费⼒⽓为 0}for (int r = 2; r <= num; r++) { // 从 2 堆依次到 num 堆,分别计算最优值for (int i = 0; i < num - r + 1; i++) { // 起始⽯⼦堆取值范围int j = i + r - 1; // 根据每次选取⽯⼦堆 r 和起始⽯⼦堆 i ,计算终⽌⽯⼦堆int sum = 0;for (int x = i; x <= j; x++) { // 计算从⽯⼦堆 i 到⽯⼦堆 j 合并时,最后两堆使⽤的⼒⽓总和 sumsum += weight[x];}// 根据动规⽅程,从局部最优解中计算当前从⽯⼦堆 i 到⽯⼦堆 j 合并所使⽤的的⼒⽓总和dp[i][j] = dp[i + 1][j] + sum; // 计算从 i ⽯⼦堆分开时,使⽤的⼒⽓总和location[i][j] = i; // 标记从第 i ⽯⼦堆分开位置for (int k = i + 1; k < j; k++) { // 需要统计从 k 【k ∈ (i, j)】⽯⼦堆分开,使⽤的⼒⽓总和int temp = dp[i][k] + dp[k + 1][j] + sum; // 计算从 k ⽯⼦堆分开时,使⽤的⼒⽓总和if (temp < dp[i][j]) {dp[i][j] = temp;location[i][j] = k;}}}}}/*** 输出*/private static void print() {System.out.println("动规数组【不同堆数合并⽯⼦所费⼒⽓】:");for (int i = 0; i < num; i++) {for (int j = 0; j < num; j++) {System.out.print(dp[i][j] + " ");}System.out.println();}System.out.println("不同堆数合并⽯⼦最省⼒⽓断开位置最优解:");for (int i = 0; i < num; i++) {for (int j = 0; j < num; j++) {System.out.print(location[i][j] + " ");}System.out.println();}}public static void main(String[] args) {// 初始化数据initData();// 计算最省最费⼒⽓值dpFindMinStrength();// 输出print();}}⽯⼦合并核⼼代码(5)输⼊输出请输⼊⽯⼦堆数量:4请输⼊每堆⽯⼦的重量:4 45 9动规数组【不同堆数合并⽯⼦所费⼒⽓】:0 8 21 430 0 9 270 0 0 140 0 0 0不同堆数合并⽯⼦最省⼒⽓分开位置最优解【下标从数组 0 开始分开】:0 0 1 20 0 1 20 0 0 20 0 0 0输⼊输出(6)总结 ⽯⼦合并问题完全提现了动态规划的核⼼思想,先求解⼦问题的解【⼦问题求解不相互独⽴,相互依赖】,然后从这些⼦问题的解中得到原问题的解,进⽽得到该问题的最优解。
石子合并问题
石子合并问题
石子合并问题是最经典的DP问题。
首先它有如下3种题型:
(1)有N堆石子,现要将石子有序的合并成一堆,规定如下:每次只能移动任意的2堆石子合并,合并花费为新合成的一堆石子的数量。
求将这N堆石子合并成一堆的总花费最小(或最大)。
分析:当然这种情况是最简单的情况,合并的是任意两堆,直接贪心即可,每次选择最小的两堆合并。
本问题实际上就是哈夫曼的变形。
(2)有N堆石子,现要将石子有序的合并成一堆,规定如下:每次只能移动相邻的2堆石子合并,合并花费为新合成的一堆石子的数量。
求将这N堆石子合并成一堆的总花费最小(或最大)。
分析:我们熟悉矩阵连乘,知道矩阵连乘也是每次合并相邻的两个矩阵,那么石子合并可以用矩阵连乘的方式来解决。
设dp[i][j]表示第i到第j堆石子合并的最优值,sum[i][j]表示第i到第j 堆石子的总数量。
那么就有状态转移公式:
代码如下:(直线)
return 0;
}
(3)问题(2)的是在石子排列是直线情况下的解法,如果把石子改为环形排列,又怎么做呢?
分析:状态转移方程为:
其中有:
代码如下:(环形)
#include <stdio.h>
#include <string.h>
#define INF 10000
#define N 205
int mins[N][N];
int maxs[N][N];
int sum[N],a[N];
int minval,maxval;
int n;
int min(int a,int b)
{
return a<b?a:b;。
小学数学石子浸水练习题
小学数学石子浸水练习题在小学数学的学习中,我们经常会遇到一些有趣的问题,这些问题能够帮助我们培养数学思维和解决问题的能力。
其中一个经典的问题就是石子浸水练习题。
该问题引发了不少学生的兴趣,并通过解决这个问题,他们能够更好地理解浮力概念、体积与容积的关系,以及数学计算与推理的方法。
问题描述:小明拿到一块石子,发现它可以在水中漂浮。
他好奇地想知道这块石子在水中的部分到底有多少。
于是他进行了以下实验:首先,他用一根线将石子系在弹簧测力计上,并浸入一个装满水的容器中。
然后,他测得此时石子的质量是5克,而测力计的示数是0.5牛。
接着,他将石子完全浸入水中,并再次测得此时测力计的示数是0.3牛。
问题一:小明想知道这块石子在水中的部分究竟有多重。
请计算出这块石子在水中的重量。
解答一:首先,我们可以根据示数的差值得出在水中的浮力。
根据阿基米德原理,浮力等于物体在液体中排开的液体的重量,也等于物体受到的浸没在液体中的重力的大小。
设石子在空气中的重力为 G1,示数为 0.5 牛,石子和测力计的总质量为 m。
则石子的重力可表示为 G1 = m * g,其中 g 是重力加速度(约等于 9.8 m/s²)。
设石子在水中的重力为 G2,示数为 0.3 牛,石子、测力计和浮力之和的质量为 m'。
则石子在水中的重力可表示为 G2 = m' * g。
由于石子在水中的浮力等于空气中石子受到的重力与石子在水中受到的重力之差,即 m * g - m' * g。
根据题目中给出的数据,可得:m * g - m' * g = 0.5牛 - 0.3牛即 m * g - m' * g = 0.2牛进一步化简上述方程,得:m * g = m' * g + 0.2牛化简为:m = m' + 0.2克根据题目中给出的数据,m = 5克,m' = ?将已知的数值代入上式,可以解得:5 = m' + 0.2m' = 5 - 0.2m' = 4.8克因此,这块石子在水中的重量为4.8克。
动态规划思想:石子合并问题
动态规划思想:⽯⼦合并问题描述:在⼀个圆形操场的四周摆放着n 堆⽯⼦。
现要将⽯⼦有次序地合并成⼀堆。
规定每次只能选相邻的2 堆⽯⼦合并成新的⼀堆,并将新的⼀堆⽯⼦数记为该次合并的得分。
试设计⼀个算法,计算出将n堆⽯⼦合并成⼀堆的最⼩得分和最⼤得分。
开始以为通过贪⼼算法可能很快解决问题,可是是⾏不通的。
⾸先我们可以把这么堆⽯⼦看成⼀列我们假如5堆的⽯⼦,其中⽯⼦数分别为7,6,5,7,100•按照贪⼼法,合并的过程如下:每次合并得分第⼀次合并 7 6 5 7 100 =11 第⼆次合并 7 11 7 100=18 第三次合并 18 7 100 =25第四次合并 25 100 =125总得分=11+18+25+125=179•另⼀种合并⽅案每次合并得分 第⼀次合并 7 6 5 7 100 ->13第⼆次合并 13 5 7 100->12第三次合并 13 12 100 ->25第四次合并 25 100 ->125总得分=13+12+25+125=175显然利⽤贪⼼来做是错误的,贪⼼算法在⼦过程中得出的解只是局部最优,⽽不能保证使得全局的值最优。
如果N-1次合并的全局最优解包含了每⼀次合并的⼦问题的最优解,那么经这样的N-1次合并后的得分总和必然是最优的。
因此我们需要通过动态规划算法来求出最优解。
在此我们假设有n堆⽯⼦,⼀字排开,合并相邻两堆的⽯⼦,每合并两堆⽯⼦得到⼀个分数,最终合并后总分数最少的。
我们设m(i,j)定义为第i堆⽯⼦到第j堆⽯⼦合并后的最少总分数。
a(i)为第i堆⽯⼦得⽯⼦数量。
当合并的⽯⼦堆为1堆时,很明显m(i,i)的分数为0; 当合并的⽯⼦堆为2堆时,m(i,i+1)的分数为a(i)+a(i+1); 当合并的⽯⼦堆为3堆时,m(i,i+2)的分数为MIN((m(i,i)+m(i+1,i+2)+sum(i,i+2)),(m(i,i+1)+m(i+2,i+2)+sum(i,i+2)); 当合并的⽯⼦堆为4堆时......代码实现如下:1 #include<stdio.h>2#define N 1003/*4 *求合并过程中5 *最少合并堆数⽬6 **/7int MatrixChain_min(int p[N],int n)8 {9//定义⼆维数组m[i][j]来记录i到j的合并过成中最少⽯⼦数⽬10 //此处赋值为-11112int m[N][N];13for(int x=1;x<=n;x++)14for(int z=1;z<=n;z++)15 {16 m[x][z]=-1;17 }1819int min=0;2021//当⼀个单独合并时,m[i][i]设为0,表⽰没有⽯⼦22for(int g = 1;g<=n;g++) m[g][g]=0;2324//当相邻的两堆⽯⼦合并时,此时的m很容易可以看出是两者之和25for(int i=1;i<=n-1;i++)26 {27int j=i+1;28 m[i][j]=p[i]+p[j];29 }3031//当相邻的3堆以及到最后的n堆时,执⾏以下循环32for(int r=3; r<=n;r++)33for(int i=1;i<=n-r+1;i++)34 {35int j = i+r-1; //j总是距离i r-1的距离36int sum=0;37//当i到j堆⽯⼦合并时最后⾥⾯的⽯⼦数求和得sum38for(int b=i;b<=j;b++)39 sum+=p[b];4041// 此时m[i][j]为i~j堆⽯⼦间以m[i][i]+m[i+1][j]+sum结果,这是其中⼀种可能,不⼀定是最优42 //要与下⾯的情况相⽐较,唉,太详细了4344 m[i][j] = m[i+1][j]+sum;4546//除上⾯⼀种组合情况外的其他组合情况47for(int k=i+1;k<j;k++)48 {49int t=m[i][k]+m[k+1][j]+sum;50if(t<m[i][j])51 m[i][j] = t;5253 }54 }55//最终得到最优解56 min=m[1][n];57return min;585960 }6162/*63 *求合并过程中64 *最多合并堆数⽬65 **/6667int MatrixChain_max(int p[N],int n)68 {69int m[N][N];70for(int x=1;x<=n;x++)71for(int z=1;z<=n;z++)72 {73 m[x][z]=-1;74 }757677int max=0;78//⼀个独⾃组合时79for(int g = 1;g<=n;g++) m[g][g]=0;80//两个两两组合时81for(int i=1;i<=n-1;i++)82 {83int j=i+1;84 m[i][j]=p[i]+p[j];85 }8687for(int r=3; r<=n;r++)88for(int i=1;i<=n-r+1;i++)89 {90int j = i+r-1;91int sum=0;92for(int b=i;b<=j;b++)93 sum+=p[b];94 m[i][j] = m[i+1][j]+sum;9596for(int k=i+1;k<j;k++)97 {98int t=m[i][k]+m[k+1][j]+sum;99if(t>m[i][j])100 m[i][j] = t;101102 }103 }104105 max=m[1][n];106return max;107108109 }110int main()111 {112int stone[N];113int min=0;114int max=0;115int n;116 scanf("%d",&n);117for(int i=1;i<=n;i++)118 scanf("%d",&stone[i]);119120 min= MatrixChain_min(stone,n);121 max= MatrixChain_max(stone,n);122123//因为题⽬要求圆的原因,要把所有情况都要考虑到,总共有n种情况。
若干取石子问题
若⼲取⽯⼦问题⼏道取⽯⼦游戏【前⾔】取⽯⼦游戏是⼀类经典的博弈问题,也是博弈问题SG函数的基础所在。
⽽它也具有⼀般博弈题的思维难度较⼤、编程量⼩等特点,因此在⽐赛时的得分情况往往呈现出两边倒的情况。
⽽其游戏的结论却经常是浅显易懂但⼜难以捉摸的,往往在⽐赛结束后,经过别⼈的⼏句话就使⼈恍然⼤悟。
本⽂将对⼏道取⽯⼦的游戏进⾏讨论,并分析思维的过程,希望读者能从中获益。
⾸先我们先来回顾⼀下最原始的取⽯⼦游戏。
即:有N堆⽯⼦,每次可以从任意⼀堆中取出若⼲⽯⼦,不能不取,两⼈轮流⾏动,最先⽆⽯⼦可取的⼈输。
⽽解决此题的⽅法便是把这N堆⽯⼦的个数进⾏异或操作,得到的值为0即为先⼿必败,否则先⼿必胜。
关于这⼀问题可以参考相关⽂献。
但仅仅靠这个模型并不能满⾜我们的要求,⾯对⼀些进⾏过变形的题⽬需要我们灵活运⽤。
下⾯我们先来看⼀个例题。
【例题1】POIXVI Stage I Pebbles题⽬⼤意:有N堆⽯⼦,开始时⽯⼦个数为A1,A2…A N。
(从左到右编号)并满⾜A1≤A2≤…≤A N,即⽯⼦个数为⾮递减数列。
两⼈轮流取⽯⼦,每次可以在任意⼀堆中取任意多个,不能不取,并且必须保证每次取完后的⽯⼦个数仍为⾮递减。
最先不能取的输。
问题分析:很显然,这道题在普通的取⽯⼦游戏上加了⼀个限制,即必须保持⽯⼦数为⾮递减数列。
这样我们便不能直接⽤原来的性质,⽽状态数也⾮常⼤,只能考虑通过⼀步步分析把问题转化。
⾸先,我们先来研究⼀些简单的情况:显然N=1时先⼿必胜。
⽽N=2时,可以发现当A1= A2时,先⼿必败,因为此时先⼿不能取A2的⽯⼦,只能在A1中取x个⽯⼦。
⽽后⼿者只需跟随先⼿者,同样在A2中取出x个即可满⾜保持A1’= A2’。
当A1< A2时,则先⼿可以从A2中取⾛A2- A1个⽯⼦。
因此先⼿必胜。
经过这个简单的分析,我们可以感觉到,由于要保证⾮递减的性质,在相邻的两堆中,可能经常会有类似N=2时的博弈发⽣。
思维拓展 数学问题
思维拓展数学问题数学是一门需要思考和解决问题的学科,它不仅仅是一些公式和计算,更是思维的拓展和锻炼。
在数学学习中,我们可以通过一些有趣的问题来拓展思维,提高解题能力。
下面,我们来看几个思维拓展的数学问题:问题一:有一堆石子,可以分成两堆,第一堆石子的数量为第二堆的两倍,如果将两堆石子的数量相加,共有63个石子,求两堆石子各有多少个?解答:设第一堆石子有x个,第二堆有y个,根据题意,可以得到以下两个方程式:x = 2y (第一堆石子的数量为第二堆的两倍)x + y = 63 (将两堆石子的数量相加共有63个石子)将第一个方程式代入第二个方程式,得到:2y + y = 633y = 63y = 21将y的值代入第一个方程式,可得到:x = 2y = 42所以,第一堆石子有42个,第二堆石子有21个。
问题二:如果有五个人,每个人都有一颗红色或者蓝色的帽子,他们不能看到自己的帽子颜色,但可以看到其他人的帽子颜色。
他们需要站在一排,从左到右依次排列,使得相邻两人的帽子颜色不同,问最少需要几种不同的排列方式?解答:设红色帽子的数量为x,蓝色帽子的数量为y,由于每个人只能戴红色或蓝色的帽子,所以有:x + y = 5又因为相邻两人的帽子颜色不能相同,所以,第一个人的帽子颜色可以是红色或蓝色,第二个人的帽子颜色只能是与第一个人不同的颜色,第三个人的帽子颜色又只能是与第二个人不同的颜色,以此类推。
因此,可以列出以下两种情况:情况一:第一个人戴红色帽子第一种排列方式:红蓝红蓝红第二种排列方式:红蓝蓝红蓝情况二:第一个人戴蓝色帽子第三种排列方式:蓝红蓝红蓝第四种排列方式:蓝红红蓝红因此,最少需要四种不同的排列方式。
问题三:有一个长为1000米的跑道,两个人从同一起点出发,一个人的速度是每秒10米,另一个人的速度是每秒15米,他们同时向同一个方向跑,如果速度较快的人追上较慢的人时,他们都会立即掉头,再开始向相反方向跑。
石子合并问题DP
⽯⼦合并问题DPSTART:2021-08-1014:29:041.问题描述:有N堆⽯⼦排成⼀排,每堆⽯⼦有⼀定的数量。
现要将N堆⽯⼦并成为⼀堆。
合并的过程只能每次将相邻的两堆⽯⼦堆成⼀堆,每次合并花费的代价为这两堆⽯⼦的和,经过N-1次合并后成为⼀堆。
求出总的代价最⼩值。
2. 输⼊输出⽰例输⼊有多组测试数据,输⼊到⽂件结束。
每组测试数据第⼀⾏有⼀个整数n,表⽰有n堆⽯⼦。
接下来的⼀⾏有n(0< n <200)个数,分别表⽰这n堆⽯⼦的数⽬,⽤空格隔开输出输出总代价的最⼩值,占单独的⼀⾏样例输⼊231 2 3713 7 8 16 21 4 18样例输出92393.分析:由题⽬我们可知,题⽬将给我们测试数据的组数,我们定义⼀个变量t来储存,⽤while(t--)来处理了这t组数据。
对于每组数据,我们⾸先会得到有n堆的⽯⼦,然后得到这n堆⽯⼦每堆⽯⼦的数⽬。
处理完数据,我们得设计算法来解题了:对于不同的顺序,我们合并⽯⼦的代价不同。
我们举个栗⼦,给定4个⽯堆,分别有1个,2个,3个,4个⽯堆,我们先全部遍历⼀遍,⽐如,先只遍历长度为2的合并,看看有什么规律:我们可以看到,有四个⽯堆,分别有1个,2个,3个, 4个⽯头,我们先执⾏长度为2的合并:我们⽤sum[i][j]表⽰从i合并到j需要多少代价,dp[i][j]表⽰合并区间[ i , j ]的⽯堆累计的代价第⼀种:1∪2==>sum[1][2]=1+2=3,dp[1][2]=3第⼆种:2∪3==>sum[2][3]=2+3=5,dp[2][3]=5第三种:3∪4==>sum[3][4]=3+4=7,dp[3][4]=7我们只有四个⽯堆,所以合并长度为2的⽅案只有这三个,然后接着我们合并长度为3的:合并区间[ 1 , 3 ]有以下两种⽅案:第⼀种:合并{1∪2,3},所以(1∪2)∪3:sum[1][3]=sum[1][2]+sum[3][3]=3+3=6dp[1][3]=sum[1][2]+sum[1][3]=3+6=9第⼆种:合并{1,2∪3},所以1∪(2∪3):sum[1][3]=sum[1][1]+sum[2][3]=1+5=6dp[1][3]=sum[2][3]+sum[1][3]=5+6=11所以合并区间[1,3]的最优⽅案是先合并1,2再合并3。
几种两人轮流取石子游戏的输赢规律及取胜策略
几种两人轮流取石子游戏的输赢规律及取胜策略有两堆或三堆石子,每堆石子数量不限,至少有一个。
两人轮流取石子,取法如下:1、每人每次至少取一个,不能不取;2、每人每次也可以取多个,甚至一次取完一堆的所有石子,但不能一次从两堆或三堆中取石子,只能从一堆中取石子。
输赢规定:轮到谁无石子可取谁就输,或者说谁取到最后的一个或者最后一堆的剩下石子谁就赢。
这个游戏有没有输赢规律?到底是先取的赢还是后取的赢?如有输赢规律,如何保证该赢的人一定能赢?即取胜的策略是什么?要解决这些问题,我们可以先易后难,先简后繁,进行探索和分析,找出输赢规律及取胜策略。
一、有两堆石子,两堆石子的个数相同。
分析:若两堆石子各有一个,则按照游戏规则,后取的必赢。
因为只有一种情况,即先取的和后取的各取一个就结束。
再细想,如果两堆石子个数超过一个,还是后取的赢。
取胜策略是每次先取的从某一堆取几个,后取的就从另一堆取几个。
这样每一轮取完后,剩下的两堆石子还是同样多。
最后一轮的情况是先取的把某一堆剩下的取完(一个或几个),后取的把另一堆剩下的取完(一个或几个)。
二、有两堆石子,两堆石子的个数不同。
分析:先取的可从个数多的一堆取几个石子,取后使两堆石子的个数相同。
这样就变成第一种情况,则先取的必赢。
策略是先从个数多的一堆取几个石子,取后使两堆石子的个数相同,然后再按照第一种情况的策略来取即可。
三、有三堆石子,其中有两堆个数一样多。
分析:先取的可先把个数不一样多的一堆取完,就变成第一种情况,所以是先取的必赢。
四、有三堆石子,个数分别是1、2、3个。
分析:若先取的把只有一个的一堆取完,则变成第二种情况,后取的赢;若先取的从两个的一堆中取一个,则后取的把三个的一堆取完,变成第一种情况,后取的赢;若先取的把两个的一堆取完,变成第二种情况,还是后取的赢。
先取的从三个的一堆中取,不论取几个,用同样的方法进行分析,后取的都有办法赢。
所以,先取的不论如何取法,后取的都有应对之策保证必赢。
石子合并问题实验报告
一、实验目的1. 了解石子合并问题的背景和意义;2. 掌握石子合并问题的解决方法;3. 提高实验操作能力和数据分析能力。
二、实验原理石子合并问题是一个经典的数学问题,主要研究如何将若干个石子合并成若干个尽可能大的石子堆。
该问题在现实生活中具有广泛的应用,如城市规划、资源分配等。
实验通过模拟石子合并过程,寻找最优的合并策略。
三、实验材料1. 石子若干;2. 纸和笔;3. 计算器。
四、实验步骤1. 准备实验材料,将石子随机分成若干堆;2. 记录每堆石子的数量;3. 按照一定的合并策略进行合并,如从数量最少的一堆开始合并;4. 记录每次合并后的石子堆数量和数量;5. 重复步骤3和4,直到所有石子合并成若干个石子堆;6. 分析实验结果,总结最优合并策略。
五、实验结果与分析1. 实验结果通过多次实验,发现以下几种合并策略:(1)从数量最少的一堆开始合并;(2)从数量最多的一堆开始合并;(3)从数量相差最小的一堆开始合并。
2. 实验分析(1)从数量最少的一堆开始合并:该策略在合并过程中可以逐渐减少石子堆的数量,但可能导致石子堆的体积差异较大。
(2)从数量最多的一堆开始合并:该策略在合并过程中可以保持石子堆的体积相对稳定,但可能导致石子堆的数量较多。
(3)从数量相差最小的一堆开始合并:该策略在合并过程中可以平衡石子堆的数量和体积,但需要花费更多的时间进行筛选。
综上所述,从数量相差最小的一堆开始合并是一种较为合理的合并策略。
六、实验结论1. 通过石子合并问题实验,了解了石子合并问题的背景和意义;2. 掌握了石子合并问题的解决方法,即从数量相差最小的一堆开始合并;3. 提高了实验操作能力和数据分析能力。
七、实验心得1. 在实验过程中,要注重观察和分析,以便找到最优的合并策略;2. 要善于总结经验,提高实验效率;3. 要注重团队合作,共同完成实验任务。
八、实验展望石子合并问题在现实生活中具有广泛的应用,未来可以从以下几个方面进行深入研究:1. 探讨不同合并策略的优缺点,寻找更优的合并策略;2. 将石子合并问题与其他实际问题相结合,如城市规划、资源分配等;3. 利用计算机技术,模拟石子合并过程,提高实验效率。
简单博弈
简单博弈问题一:A和B两个人面对两堆石头,轮流取石子,A先取。
谁先取了最后一个谁赢。
规则:只能在其中一堆取任意个(至少一个)。
现在给你两堆石子的数目n和m,你如果是A,你有没有取胜的策略?并且判断谁赢。
假设双方都用最佳策略。
题解:假设 n>m ,n m 那么如果我是A,那我先取啦m m 我一定可以让第一堆等于第二堆………下来你在其中一堆拿多少,我就在另外一堆拿多少,哈哈,你很无奈吧~~~~~如果n <> m,那么A胜;如果 n=m ,那么我是A,我先取,一定搞得两堆不相等, B看到两堆不相等,他(B)也模仿我之前赢他的策略~~~ 最后B胜总结:我制造一个平衡状态给你,你不得不破坏,那么经过你破坏,留给我一个不平衡状态,我很开心,我又可以制造另外一个平衡状态给你破坏了。
也就是说平衡状态总是我制造的,注意了 0 0就是最后的一个平衡状态,我制造的!所以是我拿走了最后一个石子。
问题二:A和B两个人面对N堆石头(a1,a2,a3…..an),轮流取石子,A先取。
谁先取了最后一个谁赢。
规则:只能在其中一堆取任意个(至少一个)。
现在告诉你多少堆石子n,然后告诉你a1,a2,a3…..an分别代表每堆石子的数目。
你如果是A,你有没有取胜的策略?并且判断谁赢。
假设双方都用最佳策略。
例题(2006普及)(取石子游戏)现有5堆石子,石子数依次为3,5,7,19,50,甲乙两人轮流从任一堆中任取(每次只能取自一堆,不能不取), 取最后一颗石子的一方获胜。
甲先取,问甲有没有获胜策略(即无论乙怎样取,甲只要不失误,都能获胜)?如果有,甲第一步应该在哪一堆里取多少?请写出你的结果: _________________________________________。
答案:有获胜策略(1分),第1次在第5堆中取32颗石子(4分)。
组合数学中的博弈问题。
题解:和二进制很大关系。
0 0 0 0 0 1 1 ←3 ---第1堆0 0 0 0 1 0 1 ←5 ---第2堆0 0 0 0 1 1 1 ←7 ---第3堆0 0 1 0 0 1 1 ←19 ---第4堆0 1 1 0 0 1 0 ←50 ---第5堆最后变成001 0 0 1 0 ---第5堆(18)--------------------0 1 2 0 2 4 4 ←代表每列有多少个1第一步:从左开始往右找第一个奇数(红色),然后找这一列的1(蓝色),随便抓一个,就是它“ 0 110 0 1 0 50 ---第5堆”第二步:在结果0 1 2 0 3 4 4中找出一些是奇数的位,再在找出来的第5堆中改变对应的位(0变1或1变0)所以最后第5堆变成001 0 0 1 0 ---第5堆(18)。
投石子的数学题二年级
投石子的数学题二年级
"投石子的数学题"可能指的是一种游戏或谜题,通常涉及一些数学概念,比如计数、加法、减法、乘法或除法。
二年级的学生通常学习的是基础的算术运算。
以下是一个简化的例子,适合二年级学生水平的投石子数学题:
题目:
小明和小红正在玩投石子的游戏。
他们轮流向一个目标投掷石子,每轮可以投掷1到3个石子。
谁先投出总数达到20个石子的,谁就赢了这个游戏。
如果小明先开始,他投了2个石子,小红接着投了3个石子,然后小明再投了1个石子。
请问:
1. 经过这三轮投掷后,总共有多少个石子被投掷了?
2. 小明接下来需要投多少个石子才能赢得游戏?
解答:
1. 经过三轮投掷后的石子总数是小明的2个加上小红的3个再加上小明的1个,所以总共是2 + 3 + 1 = 6个石子。
2. 因为游戏的目标是投掷总数达到20个石子,而目前总数是6个,所以还需要20 - 6 = 14个石子。
由于小明接下来要投掷,他可以选择投掷1到3个石子。
为了赢得游戏,他应该选择能够使得总数达到或超过20的最小数目,也
就是4(因为14 - 4 = 10,然后对方最多只能到19)。
所以他应该投掷4个石子来赢得比赛。
这个简单的游戏可以帮助孩子们练习基本的数学运算,并理解如何通过计算来确定他们的策略。
石子合并问题 三种类型
一:任意版有N堆石子,现要将石子有序的合并成一堆,规定如下:每次只能移动任意的2堆石子合并,合并花费为将的一堆石子的数量。
设计一个算法,将这N堆石子合并成一堆的总花费最小(或最大)。
此类问题比较简单,就是哈夫曼编码的变形,用贪心算法即可求得最优解。
即每次选两堆最少的,合并成新的一堆,直到只剩一堆为止。
证明过程可以参考哈夫曼的证明过程。
二:直线版在一条直线上摆着N堆石子,现要将石子有序的合并成一堆,规定如下:每次只能移动相邻的2堆石子合并,合并花费为将的一堆石子的数量。
设计一个算法,将这N堆石子合并成一堆的总花费最小(或最大)。
如果熟悉矩阵连乘对这类问题肯定非常了解。
矩阵连乘每次也是合并相邻两个矩阵(只是计算方式不同)。
那么石子合并问题可用矩阵连乘的方法来解决。
那么最优子结构是什么呢?如果有N堆,第一次操作肯定是从n-1个对中选取一对进行合并,第二次从n-2对中选取一对进行合并,以此类推……设best[i][j]表示i-j合并的最优值, sum[i][j]表示第i堆石子到第j堆石子的总数量,递推公式如下:#include <cstdlib>#include <cstdio>#include <cmath>#include <algorithm>using namespace std;#define MAXN 100int sum[MAXN];int best[MAXN][MAXN];int n, stone[MAXN];int getBest(){//初始化,没有合并,花费为0for(int i = 0; i < n; ++i){best[i][i] = 0;}//还需进行合并次数for(int v = 1; v < n; ++v){//每次合并都是一条对角线,i表示行for(int i = 0; i < n - v; ++i){//根据第v次合并,现在更新i行值可以求出列的值int j = i + v;best[i][j] = INT_MAX;int add = sum[j] - (i > 0 ? sum[i - 1] : 0);//中间断开位置,取最优值for(int k = i; k < j; ++k){best[i][j] = min(best[i][j], best[i][k] + best[k + 1][j] + add);}}}return best[0][n - 1];}int main(){scanf("%d", &n);for(int i = 0; i < n; ++i)scanf("%d", &stone[i]);sum[0] = stone[0];for(int i = 1; i < n; ++i){sum[i] = sum[i - 1] + stone[i];}int best = getBest();printf("%d\n", best);return 0;}三:圆形版如果石子是排成圆形,其余条件不变,那么最优值又是什么呢?因为圆形是首尾相接的,初一想,似乎与直线排列完全成了两个不同的问题。
石子合并问题(直线版)
⽯⼦合并问题(直线版)⽬录题⽬:⽯⼦合并(⼀)时间限制:1000 ms | 内存限制:65535 KB难度:3描述有N堆⽯⼦排成⼀排,每堆⽯⼦有⼀定的数量。
现要将N堆⽯⼦并成为⼀堆。
合并的过程只能每次将相邻的两堆⽯⼦堆成⼀堆,每次合并花费的代价为这两堆⽯⼦的和,经过N-1次合并后成为⼀堆。
求出总的代价最⼩值。
输⼊有多组测试数据,输⼊到⽂件结束。
每组测试数据第⼀⾏有⼀个整数n,表⽰有n堆⽯⼦。
接下来的⼀⾏有n(0< n <200)个数,分别表⽰这n堆⽯⼦的数⽬,⽤空格隔开输出输出总代价的最⼩值,占单独的⼀⾏样例输⼊31 2 3713 7 8 16 21 4 18样例输出9239最普通的算法O(n^3):1 #include <fstream>2 #include <iostream>3 #include <cstdio>4 #include <cstring>5 #include <cstdlib>6 #include <cmath>7using namespace std;89const int N=205;10const int INF=0x7fffffff;11int n;12int a[N],sum[N],dp[N][N];1314void f();1516int main(){17//freopen("D:\\input.in","r",stdin);18while(~scanf("%d",&n)){19 sum[0]=0;20for(int i=1;i<=n;i++){21 scanf("%d",&a[i]);22 sum[i]=sum[i-1]+a[i];23 }24 f();25 printf("%d\n",dp[1][n]);26 }27return0;28}29void f(){30for(int i=1;i<=n;i++) dp[i][i]=0;31for(int r=1;r<n;r++){32for(int i=1;i<n;i++){33int j=i+r;34if(j>n) break;35 dp[i][j]=INF;36for(int k=i;k<=j;k++){37 dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]);38 }39 dp[i][j]+=sum[j]-sum[i-1];40 }41 }42 }224ms其中,dp[i][j]代表i到j堆的最优值,sum[i]代表第1堆到第i堆的数⽬总和。
动态规划中的石子归并问题
动态规划中的⽯⼦归并问题⼀.有N堆⽯⼦,每堆的重量是w[i],可以任意选两堆合并,每次合并的花费为w[i]+w[j],问把所有⽯⼦合并成为⼀堆后的最⼩花费是多少。
因为是可以任意合并,所以每次合并的时候选最⼩的两堆合并,贪⼼即可。
⼆.有N堆⽯⼦,每堆的重量是a[i],排成⼀条直线,每次只能合并相邻的两堆,直到合成⼀堆为⽌,问最后的最⼩花费是多少。
分析:因为规定了只能合并相邻的两堆,显然不能使⽤贪⼼法。
分成⼦问题来考虑,定义dp[i][j]表⽰从第i的⽯⼦合并到第j个⽯⼦的最⼩花费,那么dp[1][N]就是问题的解。
可以推出dp[i][j] = min(dp[i][k]+dp[k+1][j]) k∈(i,j)初始时dp[i][j] = INF(i!=j) dp[i][i] = INF1 #include <iostream>2 #include <cstring>3 #include <cstdio>4 #include <string>5 #include <algorithm>6using namespace std;7int T, n;8int a[210], dp[210][210], sum[210], s[210][210];9//这⾥是数据量⽐较⼩10int INF = 99999999;11int main(){12while(scanf("%d", &n) != EOF){13 memset(sum, 0, sizeof(sum));14for(int i = 1; i <= n; i++){15 cin>>a[i];16 sum[i] = sum[i-1] + a[i];17 }18for(int i = 1; i <= n; i++){19for(int j = 1; j <= n; j++)20 dp[i][j] = INF;21 }22for(int i = 1; i <= n; i++) dp[i][i] = 0;2324for(int len = 2; len <= n; len++){ //表⽰归并的长度25for(int i = 1; i <= n-len+1; i++){ //归并的第⼀位26int j = i+len-1; //归并的最后⼀位27for(int k = i; k < j; k++){28 dp[i][j] = min(dp[i][j], dp[i][k] + dp[k+1][j] + sum[j] - sum[i-1]);29 }30 }31 }32 cout<<dp[1][n]<<endl;33 }34return0;35 }这样复杂度是O(N^3)可以利⽤四边形不等式优化到O(N^2)四边形不等式:如果对于任意的a≤b≤c≤d,有m[a,c] + m[b,d] <= m[a,d] + m[b,c]那么m[i,j]满⾜四边形不等式。
石子矩阵 博弈论
石子矩阵是博弈论中常见的一种问题。
它通常涉及两位玩家在一个石子矩阵上进行游戏,每个格子中有一定数量的石子。
玩家可以在每一回合中选择一行或一列,并从该行或列中取走任意数量的石子(至少取一个),然后将剩余的石子留给对手。
这个游戏的目标是让自己取得尽可能多的石子总数。
假设两位玩家都采取最优策略,那么我们可以使用博弈论来分析这个问题。
对于一个给定的石子矩阵,我们可以计算出每个格子中的石子数量之和,记为S。
如果S为奇数,那么先手玩家(通常为玩家1)可以采取必胜策略,即无论对手如何操作,先手玩家都能确保最终获胜;如果S为偶数,则先手玩家处于劣势,对手可以采取必胜策略。
对于先手玩家而言,他可以通过观察石子矩阵的特征来确定最佳策略。
例如,如果存在某一行或某一列的石子数量为奇数,那么先手玩家可以选择取走该行或列的所有石子,从而确保自己取得奇数数量的石子。
这样无论对手如何操作,先手玩家都能保持奇数的优势,最终获胜。
如果石子矩阵中每一行和每一列的石子数量都为偶数,那么先手玩家处于劣势,因为对手始终可以采取类似的策略来保持石子数量的偶数性。
在这种情况下,先手玩家需要通过观察石子矩阵的其他特征,如对角线上的石子数量等,来确定最佳策略。
总之,石子矩阵是一个典型的博弈论问题,通过分析石子数量的奇偶性以及其他特征,我们可以确定先手玩家是否具有必胜策略,并找到最佳的游戏策略。
1。
动态规划-石子合并
目录
• 问题描述与背景 • 动态规划基础 • 石子合并问题动态规划解法 • 案例分析与实践 • 拓展应用与变体问题 • 总结与展望
问题描述与背景
01
石子合并问题介绍
问题描述
给定一个由正整数组成的环形数组,表示一堆环形排列的石子。每次操作可以选 择相邻的两堆石子进行合并,合并的代价为两堆石子的重量之和。求将所有石子 合并为一堆的最小代价。
算法性能评估与比较
时间复杂度分析
空间复杂度分析
动态规划算法的时间复杂度通常为 O(n^3),其中n为石子的堆数。这是 因为需要枚举所有可能的区间和断点, 并进行状态转移。对于较大的n,可能 需要优化算法以降低时间复杂度。
动态规划算法的空间复杂度通常为 O(n^2),其中n为石子的堆数。这是 因为需要使用一个二维数组来存储状 态转移的结果。可以通过滚动数组等 技巧优化空间复杂度。
与其他算法的比较
除了动态规划算法外,还可以使用贪 心算法、分治算法等来解决石子合并 问题。贪心算法通常具有较低的时间 复杂度,但可能无法得到最优解。分 治算法可以将问题分解为多个子问题 分别求解,但可能涉及大量的重复计 算。动态规划算法可以在保证得到最 优解的同时,避免重复计算,问题,且子问题的最优解 可以推出原问题的最优解。
无后效性
某个阶段的状态一旦确定, 则此后过程的发展不受此 前各段状态的影响。
石子合并问题动态规
03
划解法
状态定义与转移方程
状态定义
设 $f[i][ j]$ 表示将第 $i$ 堆到第 $j$ 堆石子合并成一堆的最 小/最大代价。
明确问题的边界条件,即最小子问题的解。
定义状态
为每个子问题定义一个状态,通常用一个数 组或哈希表来存储状态值。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
• •
那么任给一个局势(a,b),怎样判断它是不是奇异局势呢?我 们有如下公式: • ak =[k(1+√5)/2],bk= ak + k (k=0,1,2,...,n 方括号 表示取整函数) • 奇妙的是其中出现了黄金分割数(1+√5)/2 = 1。618...,因此,由 ak,bk组成的矩形近似为黄金矩形,由于2/(1+√5)=(√5-1)/2, 可以先求出j=[a(√5-1)/2],若a=[j(1+√5)/2],那么a = aj, bj = aj + j,若不等于,那么a = aj+1,bj+1 = aj+1+ j + 1,若 都不是,那么就不是奇异局势。然后再按照上述法则进行,一定会遇 到奇异局势。
•
•
• • • • • •
(二)威佐夫博奕(Wythoff Game):有两堆各若干个物品,两个人轮流从 某一堆或同时从两堆中取同样多的物品,规定每次至少取一个,多者不限, 最后取光者得胜。 这种情况下是颇为复杂的。我们用(ak,bk)(ak ≤ bk ,k=0,1, 2,...,n)表示两堆物品的数量并称其为局势,如果甲面对(0,0),那么甲 已经输了,这种局势我们称为奇异局势。前几个奇异局势是:(0,0)、(1, 2)、(3,5)、(4,7)、(6,10)、(8,13)、(9,15)、(11, 18)、(12,20)。 可以看出,a0=b0=0,ak是未在前面出现过的最小自然数,而 bk= ak + k, 奇异局势有 如下三条性质: 1。任何自然数都包含在一个且仅有一个奇异局势中。 由于ak是未在前面出现过的最小自然数,所以有ak > ak-1 ,而 bk= ak + k > ak-1 + k-1 = bk-1 > ak-1 。所以性质1。成立。 2。任意操作都可将奇异局势变为非奇异局势。 事实上,若只改变奇异局势(ak,bk)的某一个分量,那么另一个分量 不可能在其他奇异局势中,所以必然是非奇异局势。如果使(ak,bk)的两 个分量同时减少,则由于其差不变,且不可能是其他奇异局势的差,因此也 是非奇异局势。
•
显然,如果n=m+1,那么由于一次最多只能取m个,所以,无论先取者拿走 多少个,后取者都能够一次拿走剩余的物品,后者取胜。因此我们发现了如何 取胜的法则:如果n=(m+1)r+s,(r为任意自然数,s≤m),那么先取者要拿 走s个物品,如果后取者拿走k(≤m)个,那么先取者再拿走m+1-k个,结果剩 下(m+1)(r-1)个,以后保持这样的取法,那么先取者肯定获胜。总之,要 保持给对手留下(m+1)的倍数,就能最后获胜。 这个游戏还可以有一种变相的玩法:两个人轮流报数,每次至少报一个, 最多报十个,谁能报到100者胜。 转发至微博
取石子问题 取石子问题
有一种很有意思的游戏,就是有物体若干堆,可 以是火柴棍或是围棋子等等 均可。两个人轮流从堆中取物体若干,规定最后取光物体者取胜。这是我国民 间很古老的一个游戏,别看这游戏极其简单,却蕴含着深刻的数学原理。下面 我们来分析一下要如何才能够取胜。 (一)巴什博奕(Bash Game):只有一堆n个物品,两个人轮流从这堆物品中 取物,规定每次至少取一个,最多取m个。最后取光者得胜。
• ••• • • Nhomakorabea • • • •
(三)尼姆博奕(Nimm Game):有三堆各若干个物品,两个人轮流从某一堆取任意多 的物品,规定每次至少取一个,多者不限,最后取光者得胜。 这种情况最有意思,它与二进制有密切关系,我们用(a,b,c)表示某种局势, 首先(0,0,0)显然是奇异局势,无论谁面对奇异局势,都必然失败。第二种奇异局 势是(0,n,n),只要与对手拿走一样多的物品,最后都将导致(0,0,0)。仔细 分析一下,(1,2,3)也是奇异局势,无论对手如何拿,接下来都可以变为(0,n, n)的情形。 计算机算法里面有一种叫做按位模2加,也叫做异或的运算,我们用符号(+)表 示这种运算。这种运算和一般加法不同的一点是1+1=0。先看(1,2,3)的按位模2加 的结果: 1 =二进制01 2 =二进制10 3 =二进制11 (+) ——————— 0 =二进制00 (注意不进位) 对于奇异局势(0,n,n)也一样,结果也是0。 任何奇异局势(a,b,c)都有a(+)b(+)c =0。 如果我们面对的是一个非奇异局势(a,b,c),要如何变为奇异局势呢?假设 a < b< c,我们只要将 c 变为 a(+)b,即可,因为有如下的运算结果: a(+)b(+)(a(+) b)=(a(+)a)(+)(b(+)b)=0(+)0=0。要将c 变为a(+)b,只要从 c中减去 c(a(+)b)即可。 在判断是不是咸佐夫博弈的奇异局势的时候,比如两个数a,b,则可以首先交换是a<b, 然后记i=b-a,如果是奇异局势,则必有m=floor(i*(1+sqrt(5.0))/2),并且b=m+i,否则 比不是奇异局势!
•
•
3。采用适当的方法,可以将非奇异局势变为奇异局势。
•
假设面对的局势是(a,b),若 b = a,则同时从两堆中取走 a 个物体,就变为了奇异局势(0,0);如果a = ak ,b > bk,那么, 取走b - bk个物体,即变为奇异局势;如果 a = ak , b < bk ,则 同时从两堆中拿走 ak - ab - ak个物体,变为奇异局势( ab - ak , ab - ak+ b - ak);如果a > ak ,b= ak + k,则从第一堆中拿走多 余的数量a - ak 即可;如果a < ak ,b= ak + k,分两种情况,第一 种,a=aj (j < k),从第二堆里面拿走 b - bj 即可;第二种, a=bj (j < k),从第二堆里面拿走 b - aj 即可。