约瑟夫问题

如果对n-1个人,最后出列人的编号为k=f (n-1);则对n个人,第一个报m数的人出列后,重排列
.当m % n = 0时,为1, ..., n-1
–则 f(n) = k
.否则,为m%n+1, ..., n, 1, m%n-1
–如果 k ≤ n-m%n则,f(n) = m%n+k
–如果 k > n-m%n则,f(n) = k - n + m%n

.T(n)=T(n-1)+ Θ(1) = Θ(n)

归纳假设:假设知道n个人,最后一个的出队列的人,不妨为f(n)

证明:基础条件,对于n=1 的时候,报数到m的肯定为自身

假设f(n-1)是前1,2,.......n-1中最后出队列的人。

如果m%n==0 第一出来的就是n,还剩余1.,2.......n-1 则 f(n)=f(n-1)

如果m%n!=0

m%n+1-------->1

m%n+2-------->2

....


n----------->n-m%n


1----------->n-m%n+1

2---------->n-m%n+2

....

m%n-1---->n-1

左侧为真实值,右侧为从新报数的值

看到如果 k=f(n-1)

if(k<=n-m%n)  真实值为f(n)=k+m%n

else 真实值为f(n)=k-(n-m%n)

// 约瑟夫问题.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
using namespace std;
/*author:surpassgood
约瑟夫问题:假设有n个,第一次报数到m的人出列,下个元素从1开始报数
知道所有的人的出列为止
*/
#define N 5//N 为总人数
#define M 2//报到M的人出列

int fun(int n)//假设n个人 最后出列的那个人
{
	
	if(n==1) return 1;
	if(M%n==0) return fun(n-1);
	else
	{
		int k=fun(n-1);
		if(k<=(n-(M%n)))
		{
			return k+(M%n);
		}
		else
			return k-(n-M%n);
	}
}


int _tmain(int argc, _TCHAR* argv[])
{
	
	cout<<fun(N)<<endl;

	return 0;
}

用循环链表的代码,如下

typedef struct node
{
	int data;
	node * next;
}node;
void create_link(node * &head,node * &tail,int n)
{
	if(n<1)
		return;
	head=new node();
	head->data=1;
	head->next=NULL;
	int i;
	node *p;
	node *pre=head;
	for(i=2;i<n+1;i++)
	{
		p=new node();
		p->data=i;
		p->next=NULL;
		pre->next=p;
		pre=p;
	}
	tail=p;
	tail->next=head;

}
void look_m(node* &head,node * &tail,int m)
{
	node *pre,*cur;
	pre=tail;
	cur=head;
	int number=0;
	int delete_number=0;
	while(cur&&cur->next!=cur)
	{
		++number;
		if(number==m)
		{
			cout<<" "<<cur->data;
			pre->next=cur->next;
			delete cur;
			cur=pre->next;
			number=0;
		}else
		{
			pre=cur;
			cur=cur->next;

		}
		
	}
	if(cur)
	{
		cout<<" "<<cur->data;
		delete cur;
		head=NULL;
		tail=NULL;
	}
	
}
int _tmain(int argc, _TCHAR* argv[])
{
	node *head,*tail;
	create_link(head,tail,9);
	look_m(head,tail,5);
	return 0;
}



附上循环链表的代码

NODE * create2(int n)//建循环链表
{
	NODE *head=new NODE;
	head->elem=1;
	head->next=head;
	NODE *cur=head;
	int i;
	for(i=2;i<=n;i++)
	{
		NODE *s=new NODE;
		s->elem=i;
		s->next=cur->next;
		cur->next=s;
		cur=s;
	}
	return head;
}


void prin(NODE *head)//打印元素
{
	
		NODE *p=head;

		
		while(p->next!=head){
			cout<<p->elem<<" ";
			p=p->next;
		}
		cout<<p->elem<<endl;
	
}
void report(NODE *head,int n,int m)//从n中报到m的删除
{
	NODE *p=head;
	NODE *r=head;
	while(r->next!=head)
	{
		r=r->next;
	}
	while(n--)
	{
		for(int s=m-1;s--;r=p,p=p->next);
		r->next=p->next;
		cout<<"  "<<p->elem<<endl;
		delete p;
		p=r->next;
	}

}


 



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值