HDU ACM Step 2.2.2 Joseph(约瑟夫环问题)

HDU ACM Step 2.2.2http://acm.hdu.edu.cn/game/entry/problem/show.php?chapterid=2§ionid=2&problemid=2

题目大意是给一个k,前k个是好人,后k个是坏人,依次不回归数数,数到m的处决,要求找到一个最小的m,使坏人们死在好人前面。

这是个约瑟夫环问题。开始想用数组模拟,死掉的出队,但是超时。后来发现前k个基本不动,完全可以不用数组,直接用下标表示。经过几次超时,进行了如下修改:去掉函数直接写在main函数中,用a[k]保存结果,去掉continue采用if-else。最后才AC,真是艰苦。

源代码:

#include <stdio.h>
int a[14]={0};
int main()
{
    int k,i,n,j;
    while(scanf("%d",&k)&&k)
    {
        if(a[k])
            printf("%d\n",a[k]);
        else{
            for(i=k+1;;++i){
                //n表示当前活的人数,j表示开始数数的人,i表示m
                for(n=k<<1,j=0;n>k;--n)
                {
                    j=(j+i-1)%n;//循环,点到的那个人
                    if(j<=k-1)
                        n=0;
                }
                if(n==k){
                    a[k]=i;
                    printf("%d\n",i);
                    break;
                }
            }
        }
    }
    return 0;
}

因为k<14,其实完全可以打表:

#include<stdio.h>
int n;
int a[20] = {0,2,7,5,30,169,441,1872,7632,1740,93313,459901,1358657,2504881,0};
int main()
{
    while(scanf("%d",&k)&&k){
      printf("%d\n",a[k]);
    }
    return 0;
}

拓展

约瑟夫环问题:n个人,编号0~n-1,从0开始报数,报到m-1的退出,剩下的人继续从0开始报数。求胜利者的编号。

可以采用动态规划方法来做。a[i]表示i个人中最后获胜者的编号,那么在0~i中,m-1首先退出,剩下的编号可以变一变。假设n=5m=3如下:

0 1 2 3 42出队

0 1 3 4→编号重排

2 3 0 1→这显然是a[i-1]的子问题

由于a[4]=0,而03,可以得到a[5]=3,考虑2号出队后的编号重排,实际上就是a[4]+3。所以可以得到公式

a[0]=0

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

源代码:

#include <stdio.h>
#define N 20
int main()
{
    int i,n,m;
    int a[N]={0};
    while(scanf("%d %d",&n,&m))
    {
        a[1]=0;
        for(i=2;i<N;i++)
            a[i]=(a[i-1]+m)%n;
    }
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值