题目:
AB两个人玩一个游戏。先任意给定一个字母串,每个人每次从中删掉任意一个字母,两个人轮流进行,如果剩余的字母序列是严格单调递增的(按字典序a < b < c <....<z),则这个人胜利。
1 模拟这个游戏,输入任意字符串(小写),能判断输赢
2 输入一字符串,如果两个人都足够聪明(即如果有赢的方案,都不会选输的方案 ),甲先开始,判断甲能赢么?
思路:
第一问非常好办,每次删除之后判断剩余字符串是否为单调递增子序列就好了。但是第二问需要引入判断。首先加入“只以完成游戏为目的的电脑”,这种级别的电脑会算出剩余数列的最长单调递增子序列,然后删除其他的元素。接着引入“会争取胜利的电脑”,这种级别的电脑会预判按照最长单调递增子序列删除元素的话,其结果是胜利还是失败,来决定是继续删除最长单调递增子序列之外的元素还是删除其中的元素来打乱次序。此外如果最后剩余了一条单调递减子序列,则胜负也能够定下来(无论怎么删,最后剩下一个元素的赢)。这也是判断手法之一。
其中有价值的代码还有计算最长单调递增子序列部分的代码。这部分采用动态规划来完成,思想如下:从0遍历至n-1,在每一个点可以计算出以该点为结尾的最长单调递增子序列长度。计算方法为:存储之前所有点的长度结果,从0遍历至当前点,判断当前点是否可以接在之前点的后面,若可以,则临时长度为该之前点的子序列长度+1,若不可以,则为1。然后计算这个临时数组中的最大值,即为当前点的最长单调递增子序列长度。这应该是个很初级的动态规划算法……
方案:
傻瓜级别电脑:随机一个位置删除。小聪明级别电脑:删除最长单调递增子序列之外的数。智慧级别电脑:计算最长单调递增子序列长度、最长单调递减子序列长度,判断这两个序列剩余元素的个数,依照这四个数据来决定下一步删除哪一个元素。
代码:
求最长子序列的代码:
1 int LongestIncreaseSubsequence(char *array,int len,int *result_array) 2 { 3 int **temp_result_array=malloc(sizeof(int *)*len);//暂存结果 4 int i; 5 for(i=0;i<=len-1;++i) 6 { 7 temp_result_array[i]=malloc(sizeof(int)*len); 8 memset(temp_result_array[i],0,sizeof(int)*len); 9 } 10 int *max_len_list=malloc(sizeof(int)*len);//以当前元素为结尾的最长子序列长度列表 11 memset(max_len_list,0,sizeof(int)*len); 12 int *temp=malloc(sizeof(int)*len); 13 memset(temp,0,sizeof(int)*len); 14 int j,max_number; 15 /////////////////////////Init over////////////// 16 for(i=0;i<=len-1;++i) 17 { 18 for(j=0;j<=i;++j) 19 if(array[j]<array[i]) 20 temp[j]=max_len_list[j]+1; 21 max_number=Max(temp,i+1); 22 if(max_number==0&&temp[max_number]==0)//前面没有比当前数小的数 23 max_len_list[i]=1; 24 else 25 { 26 max_len_list[i]=temp[max_number]; 27 for(j=0;j<=len-1;++j) 28 temp_result_array[i][j]=temp_result_array[max_number][j]; 29 } 30 temp_result_array[i][i]=1; 31 memset(temp,0,sizeof(int)*len); 32 } 33 max_number=Max(max_len_list,len); 34 for(i=0;i<=len-1;++i) 35 result_array[i]=temp_result_array[max_number][i]; 36 return max_len_list[max_number]; 37 }
其他部分的代码没什么价值,就不贴了……
浙公网安备 33010602011771号