UVA1452|LA4727-----Jump------经典的约瑟夫公式的变形(DP)

本文出自:http://blog.csdn.net/dr5459

题目地址:

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4198

题目意思:

给你编号1~n的数,每次从格k个删一个数,会有一个顺序

让你给出最后三个被删除的数

解题思路:

这题很明显就是约瑟夫的变形

假设编号从0~n-1

我们令f[1]=0   表示还剩1个时最后被删掉的一定是0

那么经典的约瑟夫公式变为f[n]=(f[n-1]+k)%n

表示剩n个时最后一个被删掉的

我们可以想到,如果我们知道剩2个的时候,被删除的是谁,剩3个的时候被删掉的是多少

然后再根据上面的公式就可以搞定了

通过本题,让我更进一步的理解了约瑟夫公式

下面是两种不同代码:


直接推出倒数被删掉的(未证明)

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;

int main()
{
    int n,k;
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&k);
        int x;
        x=(k+2)%3;
        for(int i=4;i<=n;i++)
            x=(x+k)%i;
        printf("%d ",x+1);
        x=(k+1)%2;
        for(int i=3;i<=n;i++)
            x=(x+k)%i;
        printf("%d ",x+1);
        x=0;
        for(int i=2;i<=n;i++)
            x=(x+k)%i;
        printf("%d\n",x+1);
    }
    return 0;
}


下面给出自己推的

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,k;
        scanf("%d%d",&n,&k);
        int ans1=0;
        int ans2,ans3;
        for(int i=2;i<=n;i++)
        {
            ans1 = (ans1+k)%i;
            if(i==2)//当剩下2个的,倒数第二个被删除的就是和倒数第一个不同的,答案只有0,1
            {
                ans2 = !ans1;
            }
            else if(i==3)//当剩下3个的时候,就是在0,1,2里面找不是ans1,ans2的
            {
                ans2 = (ans2+k)%i;
                int v[3];
                memset(v,false,sizeof(v));
                v[ans1] = 1;
                v[ans2] = 1;
                for(int j=0;j<3;j++)
                    if(!v[j])
                    {
                        ans3 = j;
                        break;
                    }
            }
            else
            {
                ans2 = (ans2+k)%i;
                ans3 = (ans3+k)%i;
            }
        }
        ans1 = ans1+1;
        ans2 = ans2+1;
        ans3 = ans3+1;
        printf("%d %d %d\n",ans3,ans2,ans1);


    }
    return 0;
}








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值