【数据结构】P1996 约瑟夫问题
【题目链接】
https://www.luogu.org/problem/P1996
题目描述
n个人(n<=100)围成一圈,从第一个人开始报数,数到m的人出列,再由下一个人重新从1开始报数,数到m的人再出圈,……
依次类推,直到所有的人都出圈,请输出依次出圈人的编号.
输入格式
n m
输出格式
出圈的编号
输入输出样例
10 3
3 6 9 2 7 1 8 5 10 4
说明/提示
100 ≤ m,n ≤ 100
【题解】
问题其实并不困难,但是目的就是利用题目来锻炼自己的数据结构。
给出一题五解的做法。
【解法一】
利用STL里面的list,注意指针到了链表尾部要指回链表的头部。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,m; int main()
{
list<int> List ;
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++) List.push_back(i);
list<int> ::iterator it = List.begin(),tmp; for(int i=;i<=n;i++){
for(int j=;j<m-;j++){
it++;
if( it == List.end() )
it = List.begin() ; } printf("%d ",*it);
tmp = it ;
it++;
if( it == List.end() ) it = List.begin() ;
List.erase(tmp);
}
return ;
}
STL——list
【解法二】
利用STL里面的queue,实现该过程,从队头出来,从队尾插入。
#include<cstdio>
#include<queue>
using namespace std;
int main()
{
int n,m;
queue<int> Q;
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++){
Q.push(i);
}
for(int i=;i<=n;i++){
int cur = Q.front();
Q.pop();
for(int j=;j<m-;j++){ Q.push(cur);
cur = Q.front() ;
Q.pop();
}
printf("%d%c",cur,i==n?'\n':' ');
}
return ;
}
STL—queue
【解法三】
手工实现链表
#include<cstdio>
#include<queue>
#include<cstdlib>
using namespace std;
const int N = 1e5+; typedef struct Node{
int val ;
Node * next;
}Node;
Node *head , *tail , *tmp, *p ; int main()
{
int n,m;
head = new Node ;
head -> next = NULL ;
tail = head ;
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++){
p = new Node ;
p -> val = i ;
p -> next = NULL ;
tail -> next = p ;
tail = p ;
} p = head -> next ;
tail -> next = head -> next; for(int i=;i<=n;i++){ for(int j=;j<m-;j++){
p = p->next;
}
printf("%d ",p->next->val);
tmp = p -> next ;
p -> next = tmp -> next ;
p = p -> next ;
free(tmp);
}
return ;
}
手工链表
【解法四】
手工实现队列
#include<cstdio>
#include<queue>
using namespace std;
const int N = 1e5+;
int main()
{
int n,m;
int Head = , Tail = ;
int Q[N];
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++){
Q[++Tail] = i ;
}
for(int i=;i<=n;i++){
int cur = Q[Head++];
for(int j=;j<m-;j++){
Q[++Tail] = cur ;
cur = Q[Head++];
}
printf("%d%c",cur,i==n?'\n':' ');
}
return ;
}
手工队列
【解法五】
这个题目最正解的做法是权值线段树,权值树状数组。
#include<iostream>
#include<cstdio> using namespace std; const int N=; int n,m; struct Stree
{
int l,r;
int dat;
}t[N<<];
//结构体 //建树
void build(int p,int l,int r)
{
t[p].l=l;t[p].r=r;
if(l==r)
{
t[p].dat=;
//初始化为1,表示这里是有人的
return;
}
int mid=(l+r)>>;
build(p<<,l,mid);
build(p<<|,mid+,r);
t[p].dat=t[p<<].dat+t[p<<|].dat;
} //把 x 踢出去
void change(int p,int x)
{
if(t[p].l==t[p].r)
{
t[p].dat=;
return;
}
int mid=(t[p].l+t[p].r)>>;
if(x<=mid) change(p<<,x);
else change(p<<|,x);
t[p].dat=t[p<<].dat+t[p<<|].dat;
} //查询 x 的位置
int query(int p,int x)
{
if(t[p].l==t[p].r)
return t[p].l;
//如果左边的剩余位置小于这个编号,那就在右边区域查找左边区域放不下的
if(x>t[p<<].dat) return query(p<<|,x-t[p<<].dat);
else return query(p<<,x);
} int main()
{
scanf("%d%d",&n,&m);
if(n==) return ;
build(,,n);
int pos=;
while(n)
{
pos=(pos+m-)%t[].dat+;//t[1].dat即剩余总人数
//先给 pos-1, 避免出现mod 完变成0的情况,mod完之后在 +1
//处理位置
// if(pos==0) pos=t[1].dat;
int qwq=query(,pos);
//查寻当前这个人的位置
cout<<qwq<<" ";
//输出
change(,qwq);
//踢出队伍
n--;
} return ;
}
//By Yfengzi
权值线段树
#include<iostream>
#include<cstdio>
using namespace std; const int maxn=3e4+;
int n,m,maxx;
int bit[maxn]; inline int lowbit(int x)
{
return x&-x;
}
inline void add(int pos,int x)
{
for(int i=pos;i<=maxx;i+=lowbit(i))bit[i]+=x;
}
inline int find_kth(int k)
{
int ans=,now=;
for(int i=;i>=;i--)
{
ans+=(<<i);
if(ans>maxx||bit[ans]+now>=k)ans-=(<<i);
else now+=bit[ans];
}
return ans+;
} int main()
{
scanf("%d %d",&n,&m);
maxx=n; //这里因为n后面会改变,所以先记录一下n的值。
for(int i=;i<=n;i++)bit[i]=lowbit(i);//这里完全等价于add(i,1),因为一开始都是1,所以bit[i]=i-(i-lowbit(i)+1)+1=lowbit(i)
int now=;//从1开始
while(n)
{
now=(now-+m-)%n+;//这里是小细节,本来的式子应该是(now+m-1)%n的,但是考虑如果只剩下2个元素,而我们当前要找的就是第二个元素呢?直接模就是0了,所以用一个+1 -1 的小操作更改取模运算的值域,这样就可以取到n的值了,而对别的无影响
int ans=find_kth(now);//找kth
add(ans,-);//把这个人删除
printf("%d ",ans);
n--;
}
return ;
}
权值树状数组
【数据结构】P1996 约瑟夫问题的更多相关文章
- P1996 约瑟夫问题
P1996 约瑟夫问题 广度优先搜索 我竟然寄几做对了 这个题用到了队列 下面详细解释: 我的代码: #include<iostream> #include<cstdio> # ...
- 【新知识】队列&bfs【洛谷p1996约瑟夫问题&洛谷p1451求细胞数量】
(是时候为五一培训准备真正的技术了qwq) part1 队列(FIFO) 算法简介: FIFO:First In First Out(先进先出) 队列是限定在一端进行插入,另一端进行删除的特殊线性表 ...
- [洛谷]p1996约瑟夫环 &xdoj1311
https://www.luogu.org/problemnew/show/P1996 约瑟夫环这个问题一直以来都是用循环链表写的,今天才知道有循环队列的写法.以下是要点: 1.循环队列实现环的思想, ...
- 洛谷——P1996 约瑟夫问题
P1996 约瑟夫问题 (什么?!要给学弟学妹讲约瑟夫问题?!难道就不怕我给他们讲错了吗?! 啊啊啊,为了不给学弟学妹们讲错,蒟蒻表示要临阵磨一下刀...) 题目背景 约瑟夫是一个无聊的人!!! 题目 ...
- 【vector的输出问题】 洛谷 P1996 约瑟夫问题
题目:P1996 约瑟夫问题 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 可恶啊,本来是一道不算难的题,硬是因为cin,cout同步流卡了我一天qwq 关闭cin,cout同步流 ...
- 洛谷P1996 约瑟夫问题【链表】
题目:https://www.luogu.org/problemnew/show/P1996 题意: 约瑟夫环.每次取出第m个,第2m个...... 思路: 链表维护.[感觉很少有用到链表.]非常经典 ...
- P1996 约瑟夫问题-题解(队列??明明是单循环链好吗)
一如既往的题目传送: https://www.luogu.org/problemnew/show/P1996 这里不讲数组模拟的方法(毕竟多做点题的模拟功力足以暴力出这道题),而是讲一种单循环 ...
- 【数据结构】约瑟夫问题 C语言链表实现
1.首先,我们先来了解一下什么是约瑟夫环问题: 讲一个比较有意思的故事:约瑟夫是犹太军队的一个将军,在反抗罗马的起义中,他所率领的军队被击溃,只剩下残余的部队40余人,他们都是宁死不屈的人,所以不愿投 ...
- 洛谷 P1996 约瑟夫问题
题目背景 约瑟夫是一个无聊的人!!! 题目描述 n个人(n<=100)围成一圈,从第一个人开始报数,数到m的人出列,再由下一个人重新从1开始报数,数到m的人再出圈,……依次类推,直到所有的人都出 ...
随机推荐
- slax linux的定制
由于数据结构教学的需要,需要用到linux,要求就是小,启动快,可定制性强,恰好slax正好满足要求,以下就是定制slax linux的过程记录: 什么是Slax Slax是一个基于Linux的Liv ...
- 谷歌浏览器试调网页 多出font标签
突然发现一些按钮的点击功能失效,在控制台发现该a标签中多出个font标签,导致文字区域不能触发到a标签 就算a标签宽高设置百分百 也没用. 经测试不同的浏览器情况不一样 safari就不会出现这种情况 ...
- spring+mybatis事务的readonly属性无效
在Spring配置事务中设置的read-only="true"不起作用,仍可以执行写操作:但是其他的正常.查看了一下DataSourceTransactionManager这个类的 ...
- Angular4.x+Ionic3 踩坑之路之打包时出现JAVASCRIPT HEAP OUT OF MEMORY的几种解决办法
最近开发的一个比较大型的App时打生产环境包是出现内存不足导致打包失败的问题.然后百度发现解决方法都是一样,自己试了一下都没什么暖用,心里只想用呵呵来形容了.最后经朋友介绍,技术问题还得去谷歌,git ...
- Spring Security整合JWT,实现单点登录,So Easy~!
前面整理过一篇 SpringBoot Security前后端分离,登录退出等返回json数据,也就是用Spring Security,基于SpringBoot2.1.4 RELEASE前后端分离的情况 ...
- Mapping Pocos
Mapping Pocos Example Pocos/Mappings public class Note { public int Id { get; set; } public DateTime ...
- linux下编辑VI窗口插入与编辑命令
前言 在嵌入式linux开发中,进行需要修改一下配置文件之类的,必须使用vi,因此,熟悉 vi 的一些基本操作,有助于提高工作效率. 一,模式 vi编辑器有3种模式:命令模式.输入模式.末行模式.掌握 ...
- vi启动时报错:YouCompleteMe unavailable: requires Vim 7.4.1578+如何处理?
答:源码编译安装最新的vim 以redhat为例: 1. 移除旧的vi,vim sudo yum remove vi vim -y 2. 安装ncurses库 sudo yum install ncu ...
- 阶段5 3.微服务项目【学成在线】_day02 CMS前端开发_04-vuejs研究-vuejs基础-v-model指令
<!DOCTYPE html> <html lang="en" xmlns:v‐on="http://www.w3.org/1999/xhtml&quo ...
- JAVA 基础编程练习题23 【程序 23 求岁数】
23 [程序 23 求岁数] 题目:有 5 个人坐在一起,问第五个人多少岁?他说比第 4 个人大 2 岁.问第 4 个人岁数,他说比第 3 个 人大 2 岁.问第三个人,又说比第 2 人大两岁.问第 ...