POJ 1012 Joseph

题目大意:给定一个k,代表有k个好人和k个坏人。按照约瑟夫问题的规则进行。求出最小的m,使经过k轮后,k个坏人全部被杀死。

思路:

(1)先给出约瑟夫环的递推公式:f(i)=(f(i-1)+m-1)%(n-i+1),f(0)=0;其中n代表开始时共有n人,m代表每次杀死第m个人,f(i)代表按照第i轮顺序编号,第i轮应该杀死的人的编号。按照题目要求,好人的编号始终都是0~k-1,所以一旦f(i)<k ,则不符合要求。

(2)递推公式的证明如下:令第i-1轮杀死的人的编号为f(i-1),则第i轮从f(i-1)+1开始,此时场上有n-i+1个人。存在映射:

f(i-1) --> 0 ;   f(i-1)+1 --> 1 ;  ......  ;   f(i-1)-2 --> n-i-1 ;   f(i-1)-1 --> n-i;

按照后者的编号,应该杀死的人的编号f ‘(i) = (m-1) % (n-i+1); 则 f(i) = f'(i) + f(i-1)%(n-i+1) = (f(i-1)+m-1)%(n-i+1);

(3)令答案为m,则m应该大于等于k+1进行枚举。另外,m不必递增枚举,m必须满足k+1的整数倍或者k+1的整数倍加1。证明如下:考虑第k-1轮时,此时场上还剩下k个好人和1个坏人。此时只存在两种序列 GGGG.....GGXB 或 GGGG......GGBX,显然m = t(k+1) + b,t=1,2,3....,b=0或1。

 

代码,服务器端打表

#include <iostream>
#include <algorithm>

using namespace std;

bool test(int m,int k)
{
    int n=k*2,i,j=0;
    for (i=1;i<=k;i++)
    {
        j=(j+m-1)%(n-i+1);
        if (j<k)
            return false;
    }
    return true;
}

int main()
{
    int k,ans[14],j;
    for (k=1;k<=13;k++)
    {
        for (j=1;;j++)
        {
            if (test(j*(k+1),k))
            {
                ans[k]=j*(k+1);
                break;
            }
            if (test(j*(k+1)+1,k))
            {
                ans[k]=j*(k+1)+1;
                break;
            }
        }
    }
    while (scanf("%d",&k)==1 && k!=0)
        printf("%d\n",ans[k]);
    return 0;
}



 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值