【数据结构】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的人再出圈,……依次类推,直到所有的人都出 ...
随机推荐
- java试题复盘——11月13日
上: 10. AccessViolationException异常触发后,下列程序的输出结果为( A ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 AccessViol ...
- 一台服务器配置多个mysql实例
在公司资源紧张的情况下,需要在一台服务器上部署多个数据库实例,现在就来实战一下该情况. 需要启动两个不同的端口,分别是3306和3307 [root@node1 ~]# mkdir /u01/mysq ...
- 数据库隔离级别,每个级别会引发什么问题,mysql默认是哪个级别
1.脏读 脏读是指在一个事务处理过程里读取了另一个未提交的事务中的数据. 当一个事务正在多次修改某个数据,而在这个事务中这多次的修改都还未提交,这时一个并发的事务来访问该数据,就会造成两个事务得到的 ...
- Flask 编写一个授权登录验证的模块(二)
本篇比上一篇多了重定向的功能 #!/usr/bin/env python # -*- coding: utf-8 -*- #python3 import base64 import random im ...
- 【转载】Maven安装配置+ GIt&SVN + Jenkins详细配置 软件项目管理 持续集成实验
原文地址: https://www.cnblogs.com/clownice/p/5395933.html 以下是学习笔记: Jenkins是一款开源持续集成的软件,实现集成的自动化 自动构建工具:M ...
- 通过Vagrant搭建PHP环境(一) Vagrant box添加配置
系统Windows10 Vagrant 1.8.1 VirtualBox 5.0.20 vagrant box下载地址:http://cloud.centos.org/centos/7/vagrant ...
- vue常用的修饰符
v-model修饰符 <template> <div id="demo14"> <p>-----------------模板语法之修饰符---- ...
- v-on绑定特性命名带小横杠 ‘-’与props属性中变量怎么对应
特性命名问题: 矛盾点一:html的特性不区分大小写 矛盾点二:Vue中除了模板命名,其他命名不允许出现小横杠 ‘-’ 在js文件内,命名为驼峰式,camerCase,进入html文件,自动转换成短横 ...
- <JavaScript> 匿名函数和闭包的区别
匿名函数:没有名字的函数:并没有牵扯到应用其他函数的变量问题.仅仅是没有名字. 定义方式: 1,var A = function(){ }; 2, (function (x,y){ })(2,3); ...
- CVR并发写入测试
CVR并发写入测试 测试环境: 主机:DELL Optiplex 790 系统:Windows7SP1 64bit CPU:i5-2500 3.3GB 4核 内存:8GB 硬盘:希捷 7200rpm ...