【题目链接】

https://www.luogu.org/problem/P1996

题目描述

n个人(n<=100)围成一圈,从第一个人开始报数,数到m的人出列,再由下一个人重新从1开始报数,数到m的人再出圈,……

依次类推,直到所有的人都出圈,请输出依次出圈人的编号.

输入格式

n m

输出格式

出圈的编号

输入输出样例

输入 #1

10 3
输出 #1

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 约瑟夫问题的更多相关文章

  1. P1996 约瑟夫问题

    P1996 约瑟夫问题 广度优先搜索 我竟然寄几做对了 这个题用到了队列 下面详细解释: 我的代码: #include<iostream> #include<cstdio> # ...

  2. 【新知识】队列&bfs【洛谷p1996约瑟夫问题&洛谷p1451求细胞数量】

    (是时候为五一培训准备真正的技术了qwq) part1  队列(FIFO) 算法简介: FIFO:First In First Out(先进先出) 队列是限定在一端进行插入,另一端进行删除的特殊线性表 ...

  3. [洛谷]p1996约瑟夫环 &xdoj1311

    https://www.luogu.org/problemnew/show/P1996 约瑟夫环这个问题一直以来都是用循环链表写的,今天才知道有循环队列的写法.以下是要点: 1.循环队列实现环的思想, ...

  4. 洛谷——P1996 约瑟夫问题

    P1996 约瑟夫问题 (什么?!要给学弟学妹讲约瑟夫问题?!难道就不怕我给他们讲错了吗?! 啊啊啊,为了不给学弟学妹们讲错,蒟蒻表示要临阵磨一下刀...) 题目背景 约瑟夫是一个无聊的人!!! 题目 ...

  5. 【vector的输出问题】 洛谷 P1996 约瑟夫问题

    题目:P1996 约瑟夫问题 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 可恶啊,本来是一道不算难的题,硬是因为cin,cout同步流卡了我一天qwq 关闭cin,cout同步流 ...

  6. 洛谷P1996 约瑟夫问题【链表】

    题目:https://www.luogu.org/problemnew/show/P1996 题意: 约瑟夫环.每次取出第m个,第2m个...... 思路: 链表维护.[感觉很少有用到链表.]非常经典 ...

  7. P1996 约瑟夫问题-题解(队列??明明是单循环链好吗)

    一如既往的题目传送:     https://www.luogu.org/problemnew/show/P1996 这里不讲数组模拟的方法(毕竟多做点题的模拟功力足以暴力出这道题),而是讲一种单循环 ...

  8. 【数据结构】约瑟夫问题 C语言链表实现

    1.首先,我们先来了解一下什么是约瑟夫环问题: 讲一个比较有意思的故事:约瑟夫是犹太军队的一个将军,在反抗罗马的起义中,他所率领的军队被击溃,只剩下残余的部队40余人,他们都是宁死不屈的人,所以不愿投 ...

  9. 洛谷 P1996 约瑟夫问题

    题目背景 约瑟夫是一个无聊的人!!! 题目描述 n个人(n<=100)围成一圈,从第一个人开始报数,数到m的人出列,再由下一个人重新从1开始报数,数到m的人再出圈,……依次类推,直到所有的人都出 ...

随机推荐

  1. AcWing:242. 一个简单的整数问题(树状数组)

    给定长度为N的数列A,然后输入M行操作指令. 第一类指令形如“C l r d”,表示把数列中第l~r个数都加d. 第二类指令形如“Q X”,表示询问数列中第x个数的值. 对于每个询问,输出一个整数表示 ...

  2. mybatis+mysql批量插入和批量更新、存在及更新

    mybatis+mysql批量插入和批量更新 一.批量插入 批量插入数据使用的sql语句是: insert into table (字段一,字段二,字段三) values(xx,xx,xx),(oo, ...

  3. Ubuntu18.04初始的systemd service

    Ubuntu18.04初始的systemd service 两个位置 /etc/systemd/system root@dev2:~# ls /etc/systemd/system aliyun.se ...

  4. leetcode 79. Word Search 、212. Word Search II

    https://www.cnblogs.com/grandyang/p/4332313.html 在一个矩阵中能不能找到string的一条路径 这个题使用的是dfs.但这个题与number of is ...

  5. Flask之加载静态资源

    Flask之加载静态资源 1.加载css样式 <link rel="stylesheet" href="{{ url_for('static',filename=' ...

  6. CISCN 2019 writeup

    划水做了两个pwn和两个逆向...... 二进制题目备份 Re easyGO Go语言,输入有Please字样,ida搜索sequence of bytes搜please的hex值找到字符串变量,交叉 ...

  7. 阶段5 3.微服务项目【学成在线】_day04 页面静态化_24-页面预览-页面预览测试

    通过nginx转发到预览的地址 重启nginx 添加页面预览按钮 调整下列表的列的宽度

  8. 值得学习的C语言开源项目和库

    收集一些C/C++相关的源码,如有更高效的库,请提醒我 补充上去 C/C++相关交流Q群 1414577 - 1. Webbench Webbench是一个在linux下使用的非常简单的网站压测工具. ...

  9. 福昕PDF电子文档处理套装软件中文企业版9.01

    下载地址:http://zbh.ustc.edu.cn/msiso/FoxitPDFEditor901_ZH_Setup.msi 激活码:A7000-010S0-RC900-XVF4R-9J5OM-W ...

  10. 集群架构01.Nginx初步安装配置

    1.切换163yum 源,环境介绍 [root@moban ~]# cat /etc/redhat-release CentOS release 6.5 (Final) mv CentOS-Base. ...