算法题(猜数字)

砸死牛顿的苹果 2007-02-26 10:56:05
先有0~9十个数字
任意取4个 进行排列(数字不重复)
比如说1234
然后让你猜 假如你猜
1253 提示 2正1反 1,2 数字正确处理位置也正确处理3 数字正确位置不正确
1256 提示 2正0反
直到你猜 1234 提示 4正0反 猜测结束 游戏重新开始
--------------
以上应该很简单 现在要求 人来想不重复的4位数 让电脑猜 然后根据电脑猜测的结果 给电脑相应 N正M反 的提示 直到电脑 猜出答案
当然 猜测的次数有限制 一般情况为7次以内.
请写一个最优猜测算法
...全文
701 21 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
21 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复
等我明天慢慢看了
先谢谢楼上两位
wangtk 2007-03-04
  • 打赏
  • 举报
回复
引用楼上
========================
2 + 2 * 4 + 4 - (10 - 4 * 2) - 1 = 11
每种猜测情况都是等可能的则平均猜测数为:
(1+11)/2 = 6;
因此,楼主题目得解.
========================
说明一下~这个11和1猜策的可能绝对不是等可能的~!
1次猜中的机率很小,1/(9*8*7*6) 这样还是没有0的情况

这个早有人写出了整个树的情况。。。。。



putingfei 2007-03-04
  • 打赏
  • 举报
回复
错误是copy and paste 造成的,
晚上酒喝多了,眼花了,
中文算法没有编译器纠错。
putingfei 2007-03-04
  • 打赏
  • 举报
回复
修正(5)result.ALLRIGHT == GUESS[n].ALLRIGHT
且 result.POSITIONERROR == GUESS[n].POSITIONERROR
引用楼上
========================
2 + 2 * 4 + 4 - (10 - 4 * 2) - 1 = 11
每种猜测情况都是等可能的则平均猜测数为:
(1+11)/2 = 6;
因此,楼主题目得解.
========================
说明一下~这个11和1猜策的可能绝对不是等可能的~!
1次猜中的机率很小,1/(9*8*7*6) 这样还是没有0的情况

这个早有人写出了整个树的情况。。。。。

算法中随机入队就是让每种情况等可能。

putingfei 2007-03-03
  • 打赏
  • 举报
回复
若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])。



淡蓝色2 2007-03-02
  • 打赏
  • 举报
回复
好难
淡蓝色2 2007-03-02
  • 打赏
  • 举报
回复
Mark一下,研究中...
  • 打赏
  • 举报
回复
别沉了 顶起来 相信真正的算法高手在VB版 而不是C版的

  • 打赏
  • 举报
回复
锻炼下思维而已
mkpgm 2007-02-27
  • 打赏
  • 举报
回复
像四个中先两个,开始猜12,如果有正确的最好,再看有没有反的
如果有正确的或反的,就可以确定一个,这就成了三先一
如果两者都没有,就猜34,这肯定会有一个正确的或者是反的,就可以得到一个数正确了,下面就是从三个中选一个了,
mkpgm 2007-02-27
  • 打赏
  • 举报
回复
最开始想的时候不要直接想从十个中选四个,要想从四个中选两个,五个中选两之类的,就是先从少的想起
mkpgm 2007-02-27
  • 打赏
  • 举报
回复
楼主搞这个是为了什么,我觉得没有应用的方面
fankun 2007-02-26
  • 打赏
  • 举报
回复
这个有点象破解密码。呵呵。
fankun 2007-02-26
  • 打赏
  • 举报
回复
详细点说:
1.if m=0 and n=0,取其他数字
2.if m正n反,保持m个数字位置不变,调动其他数字位置,求解,递归,直到求出m+n正,即j正0反,取出剩下数字中的4-j个,放入非正的位置(这个好像有点复杂)
3.(调动非正位置数字),求解,递归,直到j=4为止。
landy_shasha 2007-02-26
  • 打赏
  • 举报
回复
这个游戏我玩过,挺好玩的
-----------------------------------
俺兜兜里有糖
fankun 2007-02-26
  • 打赏
  • 举报
回复
第一次猜肯定是0123
if m正n反,保持m个数字位置不变,调动其他数字位置,求解,递归,if m=0 and n=0,取其他数字




bhujm 2007-02-26
  • 打赏
  • 举报
回复
既然要最优,那先讨论下如果是人来猜,怎么最快猜出吧。
  • 打赏
  • 举报
回复
如果那么容易就把思路理清楚 代码早就写出来了
fankun 2007-02-26
  • 打赏
  • 举报
回复
那你就按照你猜的思路去写代码咯。。
麦田之兔 2007-02-26
  • 打赏
  • 举报
回复
.
加载更多回复(1)

7,785

社区成员

发帖
与我相关
我的任务
社区描述
VB 基础类
社区管理员
  • VB基础类社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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