HDU 5643 King's Game

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5643


题意:

有n个人按顺序逆时针围成一个圈1,2,3,...,n。一轮第一个人从 1 开始报数,报到 1 就停止且报到1的这个人出局。

第二轮从上一轮出局的人的下一个人开始从1报数,报到2就停止且报到2的这个人出局。

第三轮从上一轮出局的人的下一个人开始从1报数,报到3就停止且报到3的这个人出局。

第 n - 1轮从上一轮出局的人的下一个人开始从 1报数,报到 n - 1就停止且报到 n - 1的这个人出局。

最后剩余的人是幸存者,请问这个人的标号是多少?


思路:

我们来考虑简单版的约瑟夫环问题,n个人站成圈,报到k的人出去,最后剩下的人的编号。

它的程序可以这么写。

int cal(int n,int k)
{
    int ans = 0;
    for(int i = 2; i <= n; i++ ) ans = ( ans + k ) % i; 
    return ans + 1; //设定编号为0~n-1 所以最后要+1恢复
}


这是一个倒推的计算过程。

有n个人编号0~n-1 那么下一轮开始的时候就是当前编号k的人第一个开始报数,我们将其重新编一下号,发现:

n个人的情况:
(k-1)淘汰  k(下一轮开始报数)

n-1个人的情况:
0(开始报数,同时也是上一轮编号为k的位置)

每一轮出去一个人,我们就将所有人重新编号,第一个开始报数的人就编为0,所以上一把编号为k的人,这一把编号为0,以此类推,那么这一把编号为x的人,上一把编号就为(x+k)%i,i是上一把的总人数。既然如此,最后一把剩余的人的编号一定为0,那么我们往前推n-1把就可以得到初始时(有n个人)他的编号是多少。

同理,我们只需要修改上面代码的一个地方就可以了,每一把出去的人报到的数不同,而且是一个倒推过程,所以最后一次报n-1,倒数第二次报n-2...


#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <sstream>
#include <queue>
#include <utility>
using namespace std;

#define rep(i,j,k) for (int i=j;i<=k;i++)
#define Rrep(i,j,k) for (int i=j;i>=k;i--)

#define Clean(x,y) memset(x,y,sizeof(x))
#define LL long long
#define ULL unsigned long long
#define inf 0x7fffffff
#define mod %100000007


int T,n;
int ans[5009];

int cal(int x)
{
    int ans = 0;
    rep(i,2,x) ans = (ans+x+1-i) % i;
    return ans+1;
}

void init()
{
    ans[1] = 1;
    ans[2] = 2;
    //rep(i,1,15) cout<<i<<" : "<<cal(i)<<endl;
    rep(i,3,5000) ans[i] = cal(i);
}



int main()
{
    init();
    cin>>T;
    while(T--)
    {
        scanf("%d",&n);
        printf("%d\n",ans[n]);
    }
    return 0;
}




  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值