POJ 1012

116 篇文章 2 订阅
27 篇文章 0 订阅

这是一道约瑟夫环问题的变种,大致意思就是,有2*k个人围成一圈,第一次从编号为1的人开始报数,报到m的人退出,接下来继续从退出的后一个人开始从1开始报,报到m的人再退出,问当m设置为多少的时候,后k个人先退出,然后前k个人才会依次退出?

思路:只要涉及到算法的题,我一般都不会做。。这道题我咋一看就是约瑟夫环的问题,建议初次做这题的人先看一下基本的约瑟夫环的问题,这道题关键就是列出递递推式。

假设ans[i]表示第i轮退出编号为ans[i]的人,

那么ans[0] = 0 

ans[i] = (ans[i-1]+m-1)%(n-i+1)

不要问我这个式子怎么推出来的,网上copy大牛的。。式子中前k个人编号为0~k-1

有了这个式子我们可以很快的求出每轮退出的人,只要判断前k个退出的人是不是含有编号1~k之间的人就可以了;

这里做一点时间上的优化,因为本题中k的值在1~14之间,所以我们可以建立一张记录表,将每次k的取值对应的m的值记录在数组里, 这样就可以避免重复计算。

#include <iostream>
using namespace std;

int main(){
    int k;
    int Joseph[14];    //记录表,将下标为k对应的m的值记录下来,避免重复计算
    memset(Joseph,0,sizeof(Joseph));
    while(cin>>k&&k){
        int n = 2*k;
        if(Joseph[k]){
            cout<<Joseph[k]<<endl;
        }
        else{
            for(int m=1;;m++){
                int result = 0;
                for(int i=1;i<=k;i++){   //用i表示第几轮
                    result = (result+m-1)%(n-i+1);
                    if(result<k)
                        break;
                }
                if(result>=k){
                    Joseph[k] = m;  //找到符合条件的值,就更新记录表
                    cout<<m<<endl;
                    break;
                }
            }
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值