zoukankan      html  css  js  c++  java
  • 约瑟夫环问题

    约瑟夫环问题:有编号从1到N的N个人坐成一圈报数,报到M的人出局,下一位再从1开始, 如此持续,直止剩下一位为止,报告此人的编号X。输入N,M,求出X。

    对于这个问题,有很多解法。包括一些基本的解法和一些优化的算法。

    基本解法一:

    这个方法比较直观,就是使用循环列表来模拟约瑟夫环。但是复杂度比较高,为O(m*n)

    具体的代码如下:

    View Code
    /*
     * =====================================================================================
     *
     *       Filename:  c069_2.c
     *
     *    Description:  
     *
     *        Version:  1.0
     *        Created:  02/26/2012 11:28:44 AM
     *       Revision:  none
     *       Compiler:  gcc
     *
     *         Author:  Hu Fangzhen (hfz), xkfzlnx@gmail.com
     *        Company:  gucas
     *
     * =====================================================================================
     
    */
    #include <stdio.h>
    #include <stdlib.h>
    #include <malloc.h>
    typedef struct _node_t
    {
        int num;
        struct _node_t *next;  
    }node_t;

    node_t *list_create(int n)
    {
        node_t *p_ret=NULL;
        if(0!=n)
        {
            int i;
            node_t *p_node=(node_t*)malloc(n*sizeof(node_t));
            if(p_node==NULL)
            {
                printf("no enough memorry\n");
                exit(-1);
            }
            i=1;
            p_ret=p_node;
            for(;i<n;i++)
            {
                p_node->num=i;
                p_node->next=p_node+1;
                p_node=p_node->next;
            }
            p_node->num=n;
            p_node->next=p_ret;
        }

        return p_ret;
    }
    int main()
    {
        int n,m;
        int i;
        node_t *p_list,*p_iter;
        printf("Enter n and m:");
        scanf("%d %d",&n,&m);
        p_list=list_create(n);
        if(p_list==NULL)
        {
            printf("can't create linklist\n");
            return -1;
        }
        p_iter=p_list;
        while(p_iter->next!=p_list)
        {
            printf("%d ",p_iter->num);
            p_iter=p_iter->next;
        }
        printf("%d \n",p_iter->num);

        p_iter=p_list;
        while(p_iter!=p_iter->next)
        {
            for(i=1;i<m-1;i++)
                p_iter=p_iter->next;
            printf("%d kicked\n",p_iter->next->num);
            p_iter->next=p_iter->next->next;
            p_iter=p_iter->next;
        }
        printf("%d left\n",p_iter->num);

        free(p_list);
    }

     参考:http://blog.minidx.com/2008/01/28/448.html

    基本解法二:

    这个方法也是比较直观的,使用数组进行模拟。

    View Code
    /*
     * =====================================================================================
     *
     *       Filename:  c069.c
     *
     *    Description:  
     *
     *        Version:  1.0
     *        Created:  02/26/2012 11:07:19 AM
     *       Revision:  none
     *       Compiler:  gcc
     *
     *         Author:  Hu Fangzhen (hfz), xkfzlnx@gmail.com
     *        Company:  gucas
     *
     * =====================================================================================
     
    */
    #include <stdio.h>
    #define NMAX 50
    int main()
    {
        int n,m;
        int arr[NMAX];
        int i,count,k;
        printf("Enter n and m:");
        scanf("%d %d",&n,&m);
        //初始化编号
        for(i=0;i<n;i++)
            arr[i]=i+1;

        count=0;
        i=0;
        k=0;//
    //不断的循环,直到剩余一个人
        while(count<n-1)
        {
            if(arr[i]!=0)
                k++;
            if(k==m)//数到m的人要被剔除
            {
                printf("%d kicked\n",arr[i]);
                arr[i]=0;//设为0表示被剔除
                k=0;//重新开始数
                count++;//计数剔除人的数目
            }
    //数组不断的循环
            i++;
            if(i==n)
                i=0;
        }
    //找到编号不为0的即为最后剩下的
        for(i=0;i<n;i++)
            if(arr[i]!=0)
                break;
        printf("%d left\n",arr[i]);
        

    }

    C++代码:

     #include <iostream>
     #include <vector>
     #include <algorithm>
     #include <iterator>
     using namespace std;
     int main(){
         int n,m;
         cin>>n>>m;
         vector<int> vr(n,0);
         for(int i=1,pos=-1;i<=n;i++){
             int j=0;
             while(j<m) {
                 pos=(pos+1)%n;
                 if(vr[pos]==0)
                     j++;
             }
             vr[pos]=i;
         }
         copy(vr.begin(),vr.end(),ostream_iterator<int>(cout," "));      
         cout<<endl;
     }

    下面的一个算法是优化算法,特别巧妙:

    View Code
    int f(int n, int m)
    {
        int i, r = 0;
        for (i = 2; i <= n; i++)
            r = (r + m) % i;
        return r+1;
    }

     这是一个递归的

    View Code
    int f(int n, int m)
    {
      if (n > 1)
        return (m + f(n - 1, m)) % m;
      else
        return 0;
    }

     其实这个两个看起来比较简单的算法是经过一些推导的。

    这儿(http://baike.baidu.com/view/717633.htm和http://wenwen.soso.com/z/q32613561.htm)有一些讲解,但是我现在还没有看明白,等以后明白之后再补上吧。 

  • 相关阅读:
    jslint报错太多的解决方式
    gulp之文件合并以及整合html中的script和link
    H5移动端下html上传图片被旋转问题
    [转]如何处理iOS中照片的方向
    [转]移动端上传图片翻转的解决方案
    [转]【鹅厂网事】全局精确流量调度新思路-HttpDNS服务详解
    phoneGap入门教程
    [转]移动端HTML5<video>视频播放优化实践
    [转]【技术心得】Last-Modified,Etag,Expire区别
    [转]浏览器缓存机制
  • 原文地址:https://www.cnblogs.com/xkfz007/p/2368531.html
Copyright © 2011-2022 走看看