求算法“调皮的小孩”(附算法描述)

Eastunfail 2003-04-21 02:00:17
【问题描述】
一群小孩在草坪上玩游戏,十分开心,一个喜欢猎奇的过路人走过来问他们:

“孩子们,你们在玩什么游戏呢?”

“我们中有一个人当裁判,剩下的人分成两队:星星队有N个人,月亮队有M个人。如果你猜对了谁是裁判,我就告诉你玩的是什么游戏。”

“好啊。不过,总得给我点提示吧?”

“那当然。你可以问我们某人是不是属于某队,而不能问某人是不是裁判。被问到的星星队的队员总是告诉你正确的答案;月亮队的队员总是告诉你错误的答案;而裁判,在你向他问奇数次的时候他会告诉你正确的答案,偶数次的时候会告诉你错误的答案。”

“哦,明白了。可以随便提问题吗?”

“你不许问任何人关于他自己的问题。例如,你不许问我:‘你是不是星星队的?’你也不能向任何一个人询问两次关于同一个人的问题。例如,你曾问过我丁丁是不是星星队的,你就不能再问我丁丁是不是月亮队的。最后,请你尽量不要问同一个人太多的问题,因为他还要接着玩呢,没时间老回答你的问题。”

过路人很聪明,不仅猜出了谁是裁判,还说出了剩下的每个人是哪个队的。你也来试试吧!

【交互】
本题是一道交互式题目,你的程序应当和测试库进行交互,而不得访问任何文件。测试库提供三个函数:GetNM,Ask,Answer,它们的作用和用法如下:

GetNM(N,M)必须首先调用,用它来获得正整数N,M的值。(2<=N+M<=500)。
Ask(Child1,Child2,T)的作用是询问。其中1<=Child1,Child2<=N+M+1,且Child1≠Child2。T非0即1,T为0表示星星队,为1表示月亮队。即询问小孩Child1“小孩Child2是不是属于T队”。若函数返回1,表示Child1回答说“是”;若函数返回0,表示Child1回答“否”。
Answer(Ans)用来告诉测试库你猜的答案。参数Ans的值为0,1,2。为0表示星星队,为1表示月亮队,为2表示裁判。你应当连续调用N+M+1次本过程,从1号开始到N+M+1号为止依次说明每个小孩的角色,注意仅有一个裁判。调用完N+M+1次本过程后,测试库会终止你的程序,切记你的程序不得自行终止。
【一个成功交互的例子】
函数调用 返回值 说明
GetNM(N,M) N=1, M=1 星星队和月亮队各有一名队员
Ask(1,2,0) 0 问小孩1:“小孩2是不是星星队的?”答:“否”
Ask(2,1,0) 1 问小孩2:“小孩1是不是星星队的?”答:“是”
Ask(3,1,1) 0 问小孩3:“小孩1是不是月亮队的?”答:“否”
Answer(2) 无 小孩1是裁判。
Answer(1) 无 小孩2是月亮队的。
Answer(0) 无 小孩3是星星队的。

【提示】
你的程序应当使用下列语句引用测试库:

uses childlib;

测试库提供的函数/过程原型为:

procedure GetNM(var N,M:integer);

function Ask(Child1,Child2,T:integer):integer;

procedure Answer(Ans:integer);

【如何测试程序】
在工作目录下建立一个文本文件child.in,文件第一行包括两个整数N,M,第二行包括N+M+1个数(数的取值为0,1,2),第k个数为小孩k所在的队,0表示星星队,1表示月亮队,2表示裁判。样例输入文件存放在用户目录中。
执行你的程序,此时测试库会产生输出文件child.log。
如果程序正常结束,child.log的第一行包含一个整数P,即被询问次数最多的小孩被问了多少次(超过10次的按10次计)。第二行包含N+M+1个数,依次为你的程序对每个孩子的猜测结果。
如果程序非法退出,则child.log会记录如下内容:“Abnormal Termination”。

在工作目录下执行程序check,会在屏幕上看到你的得分。
...全文
35 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
lymgf 2003-05-03
  • 打赏
  • 举报
回复
题目没有规定1次遍历,只是提交答案n+m+1次后,程序结束。
omrhal 2003-05-03
  • 打赏
  • 举报
回复
两个一组询问直到寻找到不同回复,最坏情况需要n+m+1次,假设再询问一次才能确定裁判是谁。然后通过原来的问题只能判断两人是不是同属一队而无法判断属于哪个队。所以要再询问啊,怎么能一次遍历呢?
lymgf 2003-05-03
  • 打赏
  • 举报
回复
1、两个一组(a,b),询问对方身份,如实例所示,直至出现答案不同为止;
2、以该组之后一人为起点,针对a的身份,问与b相同的问题,至(2*min(M,N)-1)人时,可判断出所有人的身份.
ZhangYv 2003-05-03
  • 打赏
  • 举报
回复
调用过程是系统自己提供的过程,我上面第二个回复是错的,晚上11点学校断开网线所以我没发出去。
omrhal 2003-05-03
  • 打赏
  • 举报
回复
呵呵,没看到:"只能问N+M+1次"。
楼上地,你所指的“调用过程”是什么?n+m次就可以对两队分类?没明白。
omrhal 2003-05-02
  • 打赏
  • 举报
回复
我有个想法:
-------------------------------------------------
假设一共有N个人。n个A(星星)队的,m个B(月亮)队的,1个裁判,设为p1,p2,p3……。
以楼主3个人的题目为例,我们注意到:
“Ask(1,2,0) 0 问小孩1:“小孩2是不是星星队的?”答:“否”
Ask(2,1,0) 1 问小孩2:“小孩1是不是星星队的?”答:“是” ”
问的很经典。简单分析可得出,如果有类似问答:“问a:b是不是A队的?问b:啊是不是A队的?而两人的答案是相反的”证明他们之中有一个人是裁判。
证明如下:
1。若两人是一个队的则回答应当是一样的。
2。若两人是不同的队的,那假如a是A队回答“是”,则b是A队,则b回答一定是“是”,回答是一样的,其他情况同理可证。
也就是说,我们将N个人两两分组,第一次遍历便可以找到两个之中有一个裁判的两个,设为x,y。
再去其中之一与其他队员比较最快1次,最慢min(n,m)次找出哪个是裁判,假设为x,于是便可以根据y的回答判断y是A还是B队,然后开始问y p1是不A队判断p1的归属,再问p1以判断p2的归属……依次类推。
---------------------
大家讨论一下。
ZhangYv 2003-05-02
  • 打赏
  • 举报
回复
哦,知道了。如果是3个人的话,直接利用3)。问N+M+1个人只要调用过程N+M次就可对两队分2类完毕。由于利用3)可以得出a,b的各自属于哪一个队,这时我们可以利用多余的一次问话来判断划分的两类分别是哪两个队。问题至此解决。
ZhangYv 2003-05-02
  • 打赏
  • 举报
回复
问题是:“a:b是不是A队的?问b: a是不是A队的?”
1. 如果回答同为真,则两人是同一队 (同或)
2. 如果回答同为假,则两人不是同一队 (异或)
3. 如果回答不同,则两人中有一个是裁判,需要第三人的回答判断出哪个是裁判

以上用真值表易证,由于只能问N+M+1次,也就是只允许遍历一次所以上述的说明还是不恰当。
unfbwlb 2003-05-02
  • 打赏
  • 举报
回复
up
Eastunfail 2003-04-27
  • 打赏
  • 举报
回复
Sure~

33,008

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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