链表

约瑟夫问题(洛谷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;
}
posted @ 2023-12-21 14:26  Lost-in-love  阅读(61)  评论(1)    收藏  举报