Josephus问题总结

Josephus问题:N个人排成一个圈,从其中个人从1开始报数,数到m的人自动出列,接着下一个人又从1开始报数。如此循环往复,直到只剩下一个人,则此人获胜。

假设出列的人是被毙了,这时你有两个方式:

(1)标记法:记录完所有loser,最后判断出winner时,再把loser一起毙掉

(2)直接删除法:数到一个loser毙一个,直到出现winner


上面的方法(1)便于在顺序线性表(数组)中使用,(2)便于在动态链表中使用 。


下面就两种方法给出代码:

(1)标记法

它的空间复杂度是 O(n),时间复杂度是


#include <iostream>
using namespace std;

int main(){
	int num,interval;
	int *a;
	int i,k,j;
	cout<<"How many people?";
	cin>>num;
	cout<<"interval:";           //报数间隔
	cin>>interval;

	a=new int [num];             
	for(i=0;i<num;i++){          //给每个人编号
		a[i]=i+1;
	}

	i=-1;
	k=0;

	while(1){
		for(j=0;j<interval;){
			i=(i+1)%num;        //很重要,取模法,使得循环计数
			if(a[i]!=0)j++;
		}
		if((k+1)==num) break;
		cout<<a[i]<<" ";           //输出loser
		a[i]=0;
		k++;
	}

	cout<<"\nThe winner is:";            
	for(int i=0;i<num;i++){
		if(a[i]!=0) cout<<a[i];
	}

	return 0;
}


(2)直接删除法:

空间复杂度:O(n),但是我找到loser就delete,使得堆的利用效率更高。

时间复杂度:O(3n),也就是O(n)

#include <iostream>
using namespace std;

typedef struct P{
	int num;
	struct P *next;
}Node, * Link;

int main()
{    
    void CreateList(Link &L,int n);
    Node *Start(Link L,int start);

       // 定义循环链表结点
	Link jose;
	Node *cur,*curr;               //cur是当前位置,curr跟踪cur
	int n, start, interval;
	int i,no=0;                    //no计数器

	//输入数据
	cout << "Input the number of the people: ";
	cin >> n;
	cout << "Input the interval: ";
	cin >> interval;
	cout << "Input the start position: ";
	cin >> start;

	//建立循环单链表,并初始化数据
	CreateList(jose,n);
	//设置起始位置
	cur=curr=Start(jose,start);

	cout << "\nout order:";
	while(1){
		i=1;
		while(i<interval){
			curr=cur;
			cur=cur->next;
			i++;
		}
		curr->next=cur->next;
		cout <<cur->num<<" ";
		delete cur;                    //当然可以写一个Delete函数,专门删除节点,那么我就可以不设跟踪指针了
		no++;                          //不过有delete函数的话,因为要遍历链表,那么时间复杂度更高
		if((no+1)==n) break;
		cur=curr=curr->next;
	}
	// 输出优胜者
	cout<<"\nThe winner is:"<<curr->num;  //注意,这里不用jose->num,因为,jose已经丢了,这就是不带头结点的不好之处。
	return 0;
}

void CreateList(Link &L,int n){           //建立单向循环链表(不带头结点)
	Node *p;                         //如果带上头节点的话,循环去Kill节点的时候势必受到头结点的影响,不好控制
	L=new Node;
	if(!L)exit (OVERFLOW);
	L->next=L;
	L->num=1;

	for(int i=n;i>1;i--){
		p=new Node;
		if(!p)exit (OVERFLOW);
		
		p->num=i;
		p->next=L->next;
		L->next=p;
	}
}

Node *Start(Link L,int start){
	Node *p=L;
	while(p->num<start){
		p=p->next;
	}
	return p;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值