我思故我在 发表于 2009-2-27 18:47:29

杀人游戏

不知道你是否玩过杀人游戏,这里的杀人游戏可没有法官,警察之类的人,只有土匪,现在已知有N个土匪站在一排,每个土匪都有一个编号,从1到N,每次杀人时从还活着的土匪中,编号从小到大的找第3个人,然后杀掉,继续往下,直到找遍,然后继续从剩下的土匪中,编号从小到大找到第3个活着的土匪,然后杀掉。比如,现在有10个土匪,第一次杀掉3,6,9号的土匪,第二次杀掉4,8号土匪,第三次杀掉5号土匪,第四次杀掉7号土匪,第五次杀掉10号土匪,我们看到10号土匪是最后一个被杀掉的(1,2号土匪运气好,不会被杀!)。现在给定你一个N,问你最后一个被杀掉的土匪的编号是多少?

这题自己想来很久,没想法了。不知大家有没有解法?

[ 本帖最后由 我思故我在 于 2009-2-27 22:49 编辑 ]

无心人 发表于 2009-2-27 20:08:20

和三进制关系比较大

kon3155 发表于 2009-2-27 22:32:13

原帖由 我思故我在 于 2009-2-27 18:47 发表 http://bbs.emath.ac.cn/images/common/back.gif
每次杀人时从还活着的土匪中,编号从小到大的找到3个人,然后杀掉,继续 ...

应该是“编号从小到大的找到第3个人”吧

类似猴子选大王问题!可能还有一些其他的名字,也是很经典的问题!
楼主google一下“猴子选大王”,看看有没有启示!

有一点和“猴子选大王问题”不一样,就是猴子们要围成一个圈,循环的数数

我思故我在 发表于 2009-2-27 22:51:26

是 第3个……
谢谢楼上朋友。
我看下猴子选大王。

无心人 发表于 2009-2-28 14:54:54

应该是1,2之一

没——问题 发表于 2009-3-4 06:05:44

楼上注意,应该是在你发帖之后,楼主作了修改

此题貌似过难了
终止数字生成:
#include <stdio.h>
int main()
{   int a;
       long w=3;

       for(a=0;a<50;a++)
       {      w=(3*w-1)/2;
            printf("%d\n",w);
       }
return 0;
}
注意其中应用了c整数'除'运算的向下取整
所以不用去算通项了
具体见:http://www.research.att.com/~njas/sequences/A003312
这是模拟代码:#include <stdio.h>
#define Max 100
int main()
{      int num,a,b=1,end,N;
      
      for(N=3;N<Max+1;N++)
      {      for(a=0;a<N+1;a++)num=a;
                while(b!=0)for(a=3,b=0;a<N+1;a++)if(num!=0)
                {      if(b%3==0)num=0,end=a;
                        b++;
                }
                /*if(N==end)*/printf("%d\t%d\n",N,end);
                b=1;
      }
return 0;
}


[ 本帖最后由 没——问题 于 2009-3-4 17:04 编辑 ]

我思故我在 发表于 2009-3-10 12:07:37

回复 6# 没——问题 的帖子

呵呵,此题我已解开。待到周未有空之时我写一下解题报告。

没——问题 发表于 2009-3-11 15:42:30

恩....我一直不清楚楼主是让写代码(不大可能这样吧,太容易了:Q: ),还是让给出通项公式(个人感觉又太难了...:L )

如果是代码那么就是6楼的了,两个等价(一个模拟,一个递推)

如果你在找通项公式,6楼的代码可以为你提供验证数据

我思故我在 发表于 2009-3-12 12:08:18

回复 8# 没——问题 的帖子

呵呵,其实我的本意是通过找通项公式来写代码。这样高效……

我思故我在 发表于 2009-3-13 22:07:13

今天周末,我来给个报告:
实际上,这是一个来自HDOJ的编程题。原题比这里的还难。(http://acm.hdu.edu.cn/showproblem.php?pid=2211)

下面我们先来看下原题的描述:
不知道你是否玩过杀人游戏,这里的杀人游戏可没有法官,警察之类的人,只有土匪,现在已知有N个土匪站在一排,每个土匪都有一个编号,从1到N,每次杀人时给定一个K值,从还活着的土匪中,编号从小到大的找到K个人,然后杀掉,继续往下,直到找遍,然后继续从剩下的土匪中,编号从小到大找到第K个活着的土匪,然后杀掉。比如,现在有10个土匪,K为3,第一次杀掉3,6,9号的土匪,第二次杀掉4,8号土匪,第三次杀掉5号土匪,第四次杀掉7号土匪,第五次杀掉10号土匪,我们看到10号土匪是最后一个被杀掉的(从1到K-1的土匪运气好,不会被杀!)。现在给定你一个N和一个K,问你最后一个被杀掉的土匪的编号是多少。
在Input里还说明了N和K的范围:N(N<2^31) K(3<=K<=100&&K<N)。

这道题看了范围之后就知道用暴力是绝对不行的。
肯定是找规律的题目。没有其它技巧。

假设N个人,每次找剩下的人中的第K个,那么N在一段连续的范围内有一个固定的值, 那么我们这里就需要构造这些固定的值,
第一个就一定是K(N==K),以后假设前一个是F1,则后一个是F2,
如果F1*K/(K-1)正好是整数,即F1整除(K-1),那么F2=F1*K/(K-1)-1,
如果F1不整除(K-1),那么F2=F1*K/(K-1)取整。对于K=3时,有如下的序列:
3,4,5,7,10,……
所以对于7到9之间的数字N,最后一定是7,就这个规律。

有以下数据验证(以k=3为例):
n   最后被杀的人
3   3       1
-------------
4   4       2
-------------
5   5       3
6   5
-------------
7   7       4
8   7
9   7
-------------
1010      5
1110
1210
1310
-------------
1414      6
1514
1614
1714
1814
1914
-------------
2020      7
2120
2220
2320
2420
2520
2620
2720
2820
-------------
2929   8
3029   
.   .
.   .
.   .
4229
-------------
4343   9
4443
4543
.   .
.   .
.   .
6343
6464
6564
.   .
.   .
.   .
9464
-------------
9595   10
9695
.   .
.   .
.   .
141 95
--------------
142 142    11
143 142   
.
.
.
211 142
---------------
212 212   12
.   .         .
.   .         .
.   .         .
*/

于是便可以简单的解决了程序:

#include<iostream>
using namespace std;
__int64 a;
int main()
{
        int i,j,k,n,t;
        for(i=3;i<=100;i++)
        {
                a=i;
                for(j=2;;j++)
                {
                        if( (i*a)%(i-1)==0 ) a=(i*a)/(i-1)-1;
                        else a=(i*a)/(i-1);
                        if(a>=(2147483648/i)*(i-1)) break;
                }
        }
        cin>>t;
        while(t--)
        {
                cin>>n>>k;
                for(i=1;;i++)
                {
                        if(a>n){printf("%I64d\n",a); break;}
                }
        }
        return 0;
}

OVER……
页: [1] 2
查看完整版本: 杀人游戏