约瑟夫问题(洛谷P1996)

题目描述

n 个人围成一圈,从第一个人开始报数,数到 m 的人出列,再由下一个人重新从 1 开始报数,数到 m 的人再出圈,依次类推,直到所有的人都出圈,请输出依次出圈人的编号。

输入格式

输入两个整数 n,m。

输出格式

输出一行 n 个整数,按顺序输出每个出圈人的编号。

输入输出样例

输入 

10 3

输出 

3 6 9 2 7 1 8 5 10 4

一.用结构体实现单向动态链表

#include<bits/stdc++.h>
using namespace std;
struct node{
	int data;
	node *next;
};

int main(){
	int n,m;
	scanf("%d%d",&n,&m); 
	node *head,*p,*now,*prev;
	head=new node;
	head->data=1;
	head->next=NULL;
	//分配节点一,值为1 
	now=head;
	for(int i=2;i<=n;i++){
		p=new node;
		p->data=i;
		p->next=NULL;
		now->next=p;
		now=p; 
 	}
	now->next=head;//最后一个指向第一个 
	//建立链表
	
	now=head,prev=head;
	while((n--)>1){
		for(int i=1;i<m;i++){
			prev=now;
			now=now->next; 
		}
		printf("%d ",now->data);
		prev-> next=now->next;
		delete now;
		now=prev->next;
		//输出并删除此元素 
	}
	printf("%d",now->data);
	delete now; 
	return 0;
}

二.用结构体数组实现单向静态链表

//用结构体数组实现单向静态链表
#include<bits/stdc++.h>
const int N=105;
struct node{
	int id,nextid;
}nodes[N];
int main(){
	int n,m;
	scanf("%d%d",&n,&m);
	nodes[0].nextid=1;
	for(int i=1;i<=n;i++){
		nodes[i].id=i;
		nodes[i].nextid=i+1;
	}
	nodes[n].nextid=1;
	
	int now=1,prev=1;
	while((n--)>1){
		for(int i=1;i<m;i++){
			prev=now;
			now=nodes[now].nextid;
		}
		printf("%d ",nodes[now].id);
		nodes[prev].nextid=nodes[now].nextid;
		now=nodes[prev].nextid;
	}
	printf("%d",nodes[now].nextid);
	return 0;
} 

三.用结构体数组结束双向静态链表

//用结构体数组结束双向静态链表
#include<bits/stdc++.h>
const int N=105;
struct node{
	int id,preid,nextid;
}nodes[N];
int main(){
	int n,m;
	scanf("%d%d",&n,&m);

	for(int i=1;i<=n;i++){
		nodes[i].id=i;
		nodes[i].preid=i-1;
		nodes[i].nextid=i+1;
	} 
	nodes[n].nextid=1;
	nodes[1].preid=n;
	
	int now=1;
	while((n--)>1){
		for(int i=1;i<m;i++)
			now=nodes[now].nextid;
		printf("%d ",nodes[now].id);
		int prev=nodes[now].preid,next=nodes[now].nextid;
		nodes[prev].nextid=nodes[now].nextid;
		nodes[next].preid=nodes[now].preid;
		now=next;
	}
	printf("%d",nodes[now].nextid);
	return 0;
} 

四.用一维数组实现单向静态链表

//用一维数组实现单向静态链表 
#include<bits/stdc++.h>
int nodes[150];
int main(){
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n-1;i++)
		nodes[i]=i+1;
	nodes[n]=1;
	int now=1,prev=1;
	while((n--)>1){
		for(int i=1;i<m;i++){
			prev=now;
			now=nodes[now];
		}
		printf("%d ",now);
		nodes[prev]=nodes[now];
		now=nodes[prev];
	} 
	printf("%d",now);
	return 0;
} 

五.用c++库中STL的list 

//STL:list
#include<bits/stdc++.h>
using namespace std;
int main(){
	int n,m;
	cin>>n>>m;
	list<int>node;
	for(int i=1;i<=n;i++)
		node.push_back(i);
		
	list<int>::iterator it=node.begin();//迭代器,.begin()首元素的指针,即node[0]的指针 
	while(node.size()>1){
		for(int i=1;i<m;i++){
			it++;
			if(it==node.end())it=node.begin();//.end()末尾的下一个元素的指针,类似于空指针,不指向任何元素 
		}
		cout<<*it<<" ";
		list<int>::iterator next=++it;
		if(next==node.end()) next=node.begin();
		node.erase(--it);
		it=next;
	}
	cout<<*it;
	return 0;
}

六. 一般解法

#include<bits/stdc++.h>
using namespace std;
int n,m,next[1000005];
int main(){
    cin>>n>>m;
    for(int i=0;i<n;i++)
    	next[i]=i+1;
	next[n]=1;
	int p=0;
	for(int i=1;i<=n;i++){
		for(int j=1;j<m;j++)
			p=next[p];//
		cout<<next[p]<<" ";
		next[p]=next[next[p]];
	}
	return 0;
}

七.数学解法

总人数S12345678910111213141516171819
活位置W1131357135791113151357

 

 

不难看出:当S=2^{n}+x(n,x均为自然数)时,

                      W=2x+n。

这里就留个作业,试试用数学来解这道题。

  • 8
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值