| 发表于:2007-03-03 22:41:4017楼 得分:20 |
若upperbound()表示上取整, lowerbound()表示下取整; 则从n个数之中随机选择m个进行猜测 用如下算法可保证最坏 lowerbound(n/m) + upperbound( (lowerbound(n/m) + lowerbound(m/2)) / 2 ) * m + m - (n - m * lowerbound( n/m ) ) - 1 次即可成功。 当 n = 10 ,m = 4 时,代入上式, 可得 2 + 2 * 4 + 4 - (10 - 4 * 2) - 1 = 11 每种猜测情况都是等可能的则平均猜测数为: (1+11)/2 = 6; 因此,楼主题目得解. (为避免因为编程语言造成理解障碍用中文描述,我用c++编码测试过。) 方法如下: 零,特殊情况的处理: 若 n < m; 则退出程序。 若 n = m; 则输出n为结果,退出程序。 一,初始化阶段: 1 建立一个大小为n的表(以下简称为t1,最简单用数组表示), 每一表项有如下属性(1) belong (有4个状态:yes,relevant,no,unknow(初始态)) (2) relevant (记录与某数相关) (3) 一个数组position (为一大小为m的3状态(true,false,relevant)数组, 初始状态为每一项都是true, 表示所有位置都有可能) 因为每一表项的index与n个数一一对应, 所以可以由以上属性和index确定哪个数为选定的数,并确定是否在正确位置上; 2 建立一个队列(以下简称为q),把t的index以随机方式入队; 3 建立lowerbound(n/m)个大小为m的数组 (对于每一个数组简称为m[n] 0 <= n < lowerbound(n/m) (在c/c++ 中数组从0开始) ,用来存放从q中出队的index); 4 建立一个大小为lowerbound(n/m)的数组 (以下简称为guess[n],0 <= n < lowerbound(n/m)用来与m[n]对应), 数组的每一项由如下属性:(1)allright (2)positionerror 5 建立一个大小为lowerbound(n/m)的int数组(以下简称为isrepresentative[n], 0 <= n < lowerbound(n/m)) 初始值为-1,用来与m[n]对应,表示没有成为代表; 6 建立一个大小为lowerbound(n/m)的bool数组(以下简称为empty[n],0 <= n < lowerbound(n/m) 用来与m[n]对应,表示是否为空)初始值为false; 7 建立一个队列(以下简称为q2,用于存放配对后形成的代表。) 二执行: 1 用q中的index数据分别填满设置为空的m[n], 填满一次猜测一次,把猜测的结果存入guess,其中allright存放完全正确的项数, positionerror存放位置错误的项数。若有allright+positionerror==m的项,则转到6; 2 置那些与guess中 allright + positionerror == 0的项相对应的m[e]为空 (设置empty[e] is true), 累加guess中的所有项的(allright+positionerror),若和为m,则删除q; 否则若q中的数据数大于m且存在空的m[n]则(最多大于m,且小于2m)转到1; 3 对于剩下的m[n],依照每一项的(allright+positionerror)值的大小, 把(allright+positionerror)值最大的与(allright+positionerror)值最小的配对 (如:m[k]m[j]为一对), 对于每一对m[n]选出(allright+positionerror)值较小者作代表, (m[k]与m[j]为一对,可令m[k]为代表,置其对应isrepresentative[k] 为j) 若剩下的m[n]为奇数则随便用一个配对过的且没有为代表的m[a] 与没配上对的m[z]按以上原则再配出一组; 把已经是代表的m[n]放入q2中; 4 对于从q2中出队一个代表m[n] 把它和它所代表的另一个m[k]之间 对于每对m[n][i] 与m[k][i] (0 <= i <= m-1)如下 操作(设这些操作为一函数judgeanddo(m[n][i],m[k][i])): judgeanddo(m[n][i],m[k][i]){ m[n][i],m[k][i] 进行对调,然后让人对m[n]猜测, 将猜测的结果(以下简称为result 类型与guess[n]相同) 与guess[n]中的allright和positionerror 进行比较;结果无非以下所示: (1)result.allright > guess[n].allright (2)result.positionerror > guess[n].positionerror (3)result.allright < guess[n].allright (4)result.positionerror < guess[n].positionerror (5)result.allright > guess[n].allright 且 result.positionerror > guess[n].positionerror 根据以上情况更新表t1: 对于(1) t1[ m[n][i] ].belong = yes; 除 t1[ m[n][i] ].position[ m[n][i] ]外的所有位置都为false. t1[ m[k][i] ].belong = no; 更新所有与这两项相关的项目; 检查t1中是否有m个条目已知, 且位置确定(包括为单一和互相约束可判断的两种情况) 若有则输出结果结束程序。 对于(2)t1[ m[n][i] ].belong = yes; t1[ m[n][i] ].position[ m[n][i] ] = false; t1[ m[k][i] ].belong = no; 更新所有与这两项相关的项目; 检查t1中是否有m个条目已知, 且位置确定(包括为单一和互相约束可判断的两种情况) 若有则输出结果结束程序。 对于(3)t1[ m[n][i] ].belong = yes; 除 t1[ m[n][i] ].position[ m[n][i] ]外的所有位置都为false. t1[ m[k][i] ].belong = no; 更新所有与这两项相关的项目; 检查t1中是否有m个条目已知, 且位置确定(包括为单一和互相约束可判断的两种情况) 若有则输出结果结束程序。 对于(4)t1[ m[n][i] ].belong = yes; t1[ m[n][i] ].position[ m[k][i] ] = false; t1[ m[k][i] ].belong = no; 更新所有与这两项相关的项目; 检查t1中是否有m个条目已知, 且位置确定(包括为单一和互相约束可判断的两种情况) 若有则输出结果结束程序。 对于(5)t1[ m[n][i] ].belong = relevant; t1[ m[n][i] ].relevant = m[k][i]; t1[ m[n][i] ].position[ m[n][i] ] = relevant; t1[ m[k][i] ].belong = relevant; t1[ m[k][i] ].relevant = m[n][i]; t1[ m[k][i] ].position[ m[k][i] ] = relevant; judgeanddo(m[n][i],m[k][i+1]) } 5 检索t1,找出答案,若不能得出答案,则说明猜测人有欺骗行为,给出提示,退出。 6 把该项重复调用(0 <= i <(m+1)/2) judgeanddo(m[n][i],m[n][m - i])。 | | |
|