链表
约瑟夫问题(洛谷P1996)
题目大意
有n个人,编号为1~n,按顺序围成一圈,第一个人从1开始报数,数到m的人出列,下一个人重新从1开始报数,直所有人出列,给出出列顺序。
解题思路
使用链表节点模拟人,将出列转化为链表的删除节点操作
动态链表
#include<bits/stdc++.h>
using namespace std;
struct node{
int v;
node*next;
};
int main(){
int n,m;
cin>>n>>m;
node*head,*p,*now,*prev;
head=new node;head->v=1;head->next=nullptr;
now=head;
for(int i=2;i<=n;i++){ //尾插法插入链表节点
p=new node;p->v=i;p->next=nullptr;
now->next=p;
now=p;
}
now->next=head;
now=head;prev=head;
while((n--)>1){
for(int i=1;i<m;i++){ //每m个数出队
prev=now;
now=now->next;
}
cout<<now->v<<" ";
prev->next=now->next;
delete now;
now=prev->next;
}
cout<<now->v<<" ";
delete now;
return 0;
}
单向静态链表
#include<bits/stdc++.h>
const int N=1e2+5;
using namespace std;
struct node{
int v,next;
}l[N];
int main(){
int n,m;
cin>>n>>m;
l[0].next=1;
for(int i=1;i<=n;i++){
l[i].v=i;
l[i].next=i+1;
}
l[n].next=1;
int now=1,prev=1;
while((n--)>1){
for(int i=1;i<m;i++){
prev=now;
now=l[now].next;
}
cout<<l[now].v<<" ";
l[prev].next=l[now].next;
now=l[prev].next;
}
cout<<l[now].next<<" ";
return 0;
}
双向静态链表
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
struct node{
int v,prev,next;
}l[N];
int main(){
int n,m;
cin>>n>>m;
l[0].next=1;
for(int i=1;i<=n;i++){
l[i].v=i;l[i].next=i+1;
l[i].prev=i-1;
}
l[n].next=1;
l[1].prev=n;
int now=1;
while((n--)>1){
for(int i=1;i<m;i++)now=l[now].next;
cout<<l[now].v<<" ";
int prev=l[now].prev,next=l[now].next;
l[prev].next=next;
l[next].prev=l[now].prev;
now=next;
}
cout<<l[now].next<<" ";
return 0;
}
一维数组实现单向静态链表
#include<bits/stdc++.h>
using namespace std;
const int N=1e2+5;
int l[N];
int main(){
int n,m;
cin>>n>>m;
for(int i=1;i<n;i++)l[i]=i+1;
l[n]=1;
int now=1,prev=1;
while((n--)>1){
for(int i=1;i<m;i++){
prev=now;
now=l[now];
}
cout<<now<<" ";
l[prev]=l[now];
now=l[prev];
}
cout<<now<<" ";
return 0;
}
STL list
#include<bits/stdc++.h>
using namespace std;
int main(){
int n,m;
cin>>n>>m;
list<int>l;
for(int i=1;i<=n;i++)l.push_back(i);
list<int>::iterator it=l.begin();
while(l.size()>1){
for(int i=1;i<m;i++){
it++;
if(it==l.end())it=l.begin();
}
cout<<*it<<" ";
auto next=++it;
if(next==l.end())next=l.begin();
l.erase(--it);
it=next;
}
cout<<*it<<" ";
return 0;
}
队列安排(洛谷P1160)
题目大意
有n个人,编号为1~n,初始队列为1号一个人,入队方式为指定插入编号i同学的左边或右边,删去m个同学,求剩余队列同学的编号
解题思路
对链表查找,添加,删除,遍历的操作。考虑遍历查找时间复杂度为O(n),使用数组存储编号对应链表节点位置的迭代器,实现O(1)级别查找。
未知的代码
#include<bits/stdc++.h>
using namespace std;
#define ITER list<int>::iterator
const int N=1e5+5;
ITER pos[N]; //记录编号对应的链表节点
list<int>l;
bool vis[N]; //记录是否删除
int main(){
int n,m,k,p;
cin>>n;
l.push_back(1);
pos[1]=l.begin();
auto insert=[&](int k,int p,int v){
if(p)pos[v]=l.insert(next(pos[k]),v); //p==1,右插,迭代器+1
else pos[v]=l.insert(pos[k],v);
};
for(int i=2;i<=n;i++){
cin>>k>>p;
insert(k,p,i);
}
cin>>m;
for(int i=1;i<=m;i++){
cin>>k;
if(!vis[k])l.erase(pos[k]);
vis[k]=true;
}
for(auto&it:l)cout<<it<<" ";
return 0;
}

浙公网安备 33010602011771号