老李飞刀

人生最重要的不是握一手好牌,而是把坏牌打好

导航

统计

公告

约瑟夫环


约瑟夫环是一个数学的应用问题:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列。

n=总人数, k=开始报数, m=数到出列


实例1:

 有17个人围成一圈(编号0~16),从第0号的人开始从1报数,凡报到3的倍数的人离开圈子,然后再数下去,直到最后只剩下一个人为止,问此人原来的位置是多少号?


Code A :一般方法,用数组来模拟过程
static void JosephusA()
        {
            int[] ren = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
            var j = 17;//还在的人数
            var h = 0;//下标
            var k = 1;//到三出圈计数
            while (j != 1)//只有一个人时结束循环
            {
                if (h == 17) h = 0;//下标超出就置0,围成圈
                if (ren[h] == 1 && k == 3)
                {
                    ren[h] = 0;
                    k = 1;
                    j--;
                }
                else
                {
                    if (ren[h] == 1)
                    {
                        k++;
                    }
                }

                h++;
            }

            for (int z = 0; z < 17; z++)
            {
                if (ren[z] == 1)
                {
                    Console.WriteLine("N={0}", z);
                }
            }
        }
N=10


Code B: 数学法
 static void JosephusB(int n, int k, int m)
        {
            int index = k;

            for (int i = 2; i <= n; i++)
            {

                index = (index + m) % i;
            }

            Console.WriteLine(index);
        }


Code C: 链表法

 

public static void JosephusC(int n, int k, int m)
        {
            /*
            *已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。
            *从编号为k的人开始报数,数到m的那个人出列;
            *他的下一个人又从1开始报数,数到m的那个人又出列;
            *依此规律重复下去,直到圆桌周围的人全部出列。
            */

            Link head = new Link() { Value = "1" };
            Link node = head;
            for (int i = 2; i <= n; i++)
            {
                node.Next = new Link();
                node = node.Next;
                node.Value = i.ToString();
            }
            node.Next = head;
            //循环链表建立完毕
            Link cur = head;
            //指针移动到第K个人
            for (int i = 1; i < k; i++)
            {
                cur = cur.Next;
            }
            //开始报数
            do
            {
                for (int i = 1; i < m - 1; i++)
                {
                    cur = cur.Next;
                }
                //Console.WriteLine(cur.Next.Value);
                cur.Next = cur.Next.Next;//删除第m个人
                cur = cur.Next;//指针指向m+1
            } while (cur != cur.Next);//仅剩下一个人,报数结束
            Console.WriteLine(cur.Value);
        }
        /// <summary>
        /// 循环链表节点
        /// </summary>
        public class Link
        {
            public string Value;
            public Link Next;
        }


 

优点

缺点

应用场景

Code A
  • 代码简单易懂
  • 算法复杂度高
  • 代码量过大
  • 一般性的项目代码
Code B
  • 算法复杂度低
  • 代码优雅
  • 代码太过简单,需要一定数学基础
  • 增加沟通成本
  • 面试
  • 算法研究
  • Demo
Code C
  • 代码简单易懂
  • 使用到了数据结构 链表
  • 算法复杂度高
  • 代码量过大
  • 教学中

posted on 2011-09-09 23:19 老李飞刀 阅读(48) 评论(0) 编辑 收藏