• poj 1012 Joseph (约瑟夫问题)


    Joseph
    Time Limit: 1000MS   Memory Limit: 10000K
    Total Submissions: 47657   Accepted: 17949

    Description

    The Joseph's problem is notoriously known. For those who are not familiar with the original problem: from among n people, numbered 1, 2, . . ., n, standing in circle every mth is going to be executed and only the life of the last remaining person will be saved. Joseph was smart enough to choose the position of the last remaining person, thus saving his life to give us the message about the incident. For example when n = 6 and m = 5 then the people will be executed in the order 5, 4, 6, 2, 3 and 1 will be saved. 

    Suppose that there are k good guys and k bad guys. In the circle the first k are good guys and the last k bad guys. You have to determine such minimal m that all the bad guys will be executed before the first good guy. 

    Input

    The input file consists of separate lines containing k. The last line in the input file contains 0. You can suppose that 0 < k < 14.

    Output

    The output file will consist of separate lines containing m corresponding to k in the input file.

    Sample Input

    3
    4
    0
    

    Sample Output

    5
    30
    
    

    Source

    约瑟夫问题的变形,開始对题意就理解了好久。这类题目主要要找到中间的公式;这道题就要知道 当前出局的位置 = (前一个出局的位置+m-1)%(2k-(k-1);

    是从0開始数。这就是一个通式;明确了这个公式这个题相当于就做出了一半;这中间另一个判别的条件,就是假设当前的位置假设<k,说明这样的情况就不满足了;

    第一种方法:就直接能够对m的值进行枚举。利用判别条件,找出合适的m值;

    以下是代码;这样的思路好像200ms能够过。

    //暴力+枚举
    #include <cstdio>
    #include <cstring>
    int main()
    {
        int k;
        int ans[20];//储存当前的位置
        int Joseph[20]={0}; //储存符合条件的m的值
        for(k=1;k<14;k++)
        {
            int m=1;
            memset(ans,0,sizeof(ans));
            for(int i=1;i<=k;i++)
            {
                ans[i]=(ans[i-1]+m-1)%(2*k-i+1); //递推公式
                if(ans[i]<k)
                {
                    i=0;
                    m++;
                }
            }
            Joseph[k]=m;
        }
      while(scanf("%d",&k)&&k!=0)
       {
           printf("%d
    ",Joseph[k]);
       }
       return 0;
    }
    要想0ms过的,直接得出结果数组,然后再提交。

    //直接枚举 0ms
    #include <cstdio>
    #include <cstring>
    int main()
    {
        int k;
      int Joseph[]={0,2,7,5,30,169,441,1872,7632,1740,93313,459901,1358657,2504881,1245064};
      while(scanf("%d",&k)&&k!=0)
       {
           printf("%d
    ",Joseph[k]);
       }
       return 0;
    }
    
    另外一种方法,要挖掘题目中的隐含条件,我看了好久都没看出来,代码是參考别人的,这样的46ms就能够过;优化了不少。

    题目中的隐含条件;仅仅剩下一个坏人的时候,下一个报数的人要么是第1个人,要么是第k+1个人。所以间隔就是m=s*(k+1)或者是 m=s*(k+1)+1;

    粗略的证明一下。參考别人的:(这里我也还有点没懂)

    仅剩一个坏人,圈长为k+1;设下一个报数人为第一个人时的时间间隔为m1;下一个报数人为第k+1个人时的时间间隔为m2。

    由 (1+m1)%(k+1)=1 得出 m1= s*(k+1);

       (k+1+m2)%(k+1)=1  得出 m2=s*(k+1)+1;

    这样我们就能够对m的枚举优化剪枝,m是(k+1)的倍数或者是他的倍数+1;

    #include <cstdio>
    #include <cstring>
    bool Joseph(int k,int m)
    {
        int n=2*k,x=0;
        while(n>k)
        {
            x=(x+m-1)%n;//递推公式,算出当前出局的位置
            if(x<k) //判别条件
                return false;
            n--;
        }
        return true;
    }
    int main()
    {
        int k;
        int result[20]={0};
        for(k=1;k<14;k++)
        {
            for(int i=k+1;;i+=k+1) //对m枚举进行优化
            {
                if(Joseph(k,i)) //m是k+1的倍数或者倍数+1
                {
                    result[k]=i;
                    break;
                }
                else if(Joseph(k,i+1))
                {
                    result[k]=i+1;
                    break;
                }
            }
        }
        while(scanf("%d",&k)&&k)
        {
            printf("%d
    ",result[k]);
        }
    }
    
    

    总结一下:对于这一类题型要读懂题目的题意。挖掘题目的隐含条件,多构思。理清思路才開始动手写。





  • 相关阅读:
    vue+elementUI实现权限的部门管理
    vue+elementUI实现权限的部门管理
    LeetCode
    LeetCode
    LeetCode
    LeetCode
    20 种最奇怪的编程语言
    WinForm导出文件
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
  • 原文地址:https://www.cnblogs.com/blfshiye/p/5198581.html
Copyright © 2020-2023  润新知