队列:一边入队,一边出队

queue、双端队列deque、优先队列priority_queue

优先队列:因为优先队列本质是堆,注意比较函数的写法

struct node{
	string name;
	int pri;
	friend bool operator < (node f1,node f2){
		return f1.pri<f2.pri;   //友元函数,写在结构体里面的,意思时价格大的优先!!!是反的 
	}
};
priority_queue<node> q;
struct node{
	string name;
	int pri;
};
//写在外面
struct cmp{
	bool operator () (node a,node b){
		return a.pri>b.pri;
	}
}; 
//定义的时候
priority_queue<node,vector<node>, cmp> q; ///greater(),换为了cmp
//如果数据庞大,那么使用引用来提高效率
const node &a 

  

 

一本通上面的题目

1、周末舞会

一边出队,马上入队

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;

int l1,r1,l2,r2;
int one[101],two[101];
int n1,n2,m;

int main(){
	cin>>n1>>n2>>m;
	for(int i=1;i<=n1;i++) one[i]=i;
	for(int i=1;i<=n2;i++) two[i]=i;
	l1=1;l2=1;r1=n1;r2=n2;
	for(int i=1;i<=m;i++){
		cout<<one[l1]<<" "<<two[l2]<<endl;
		
		one[++r1]=one[l1];
		two[++r2]=two[l2];
		l1++;
		l2++;
	}
return 0;
}

2、Blah数集

两个头指针

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int m,n;
long long stack[1000000];

int main(){
	while(cin>>m>>n){
		int two=1,three=1,rear=2; //队列需要两个指针,这里有两个头指针 
		stack[1]=m;
		while(rear<=n){
			long long t1=stack[two]*2+1;
			long long t2=stack[three]*3+1;
			long long t=min(t1,t2);
			if(t1<t2) two++;
			else three++;
			if(t==stack[rear-1]) continue;//去重 
			else stack[rear++]=t;//否则就加入 
		}
		cout<<stack[n]<<endl;;
	}
return 0;
}

 

1334:【例2-3】围圈报数

注意一下now一开始应该是从n开始的,因为代码顺序问题

next[i]=i+1  next[n]=1

#include<iostream>
#include<stdio.h>
#include<cmath>
#include<cstring> 
#include<queue>
using namespace std;
#define INF 1e9+10

int next[101];
int main(){
	int n,m;
	cin>>n>>m;
	int out=0,ans=1;
	for(int i=1;i<n;i++) next[i]=i+1;
	next[n]=1;
	int now=n;
	while(out<n){
		while(ans<m){
			now=next[now];
			ans++;
		}
		cout<<next[now]<<" ";
		out++;
		next[now]=next[next[now]];
		ans=1;
	}
	
	return 0; 
	
	
} 

 

类似的一个题:猴子选大王

2<=n<=1000,2<=k<=10^9

输出最后一只猴子,每一次出队的猴子是对剩下的猴子总数remain取余为k的猴子

这里有一个细节就是k需要对n进行取模计算(每一次都需要,因为总数会减少),不然一次次的数下去会超时

#include<iostream>
#include<stdio.h>
#include<cmath>
#include<cstring> 
#include<queue>
using namespace std;
#define INF 1e9+10
struct monk{
	int id,next;
}a[1010]; 
int main(){
	int n,k,remain;
	cin>>n>>k;
	for(int i=1;i<n;i++){
		a[i].id=i;a[i].next=i+1;
	}
	a[n].id=n;a[n].next=1;
	remain=n;
	int kk=k%remain;
	if(kk==0) kk=remain; //!!!
	int cur=1,pre=n,count=0;
	while(remain>1){
		count++;
		if(count==kk){
			a[pre].next=a[cur].next;
			remain--;
			count=0;
			kk=k%remain;   //每一次都需要取模 
			if(kk==0) kk=remain;
		}
		else pre=cur;
		cur=a[cur].next;
	} 
	cout<<a[cur].id<<endl;
	return 0; 
	
	
} 

 

and一个 取牌游戏

k张纸牌,n-1个朋友,n<=k<=100000,k是n的倍数,纸牌中有m=k/n张 good牌和k-m张bad牌,小明想要所有的good牌

游戏开始时候,会发给小明右手边的人,每发完一个人,就把接下来的p张牌往后移,逆时针发牌,需要输出所有的good牌所在位置(升序)

#include<iostream>
#include<stdio.h>
#include<cmath>
#include<string> 
#include<queue>
#include<algorithm>
using namespace std;
#define maxn 1500000
//这里需要推算出大概的数据范围:k+10*n*(100000/n)=1100000 
int a[maxn],b[maxn];
//a是牌的队列,b是小明拿到牌的队列 
int n,k,p; 
int main(){
	cin>>n>>k>>p;
	int front=0,tail=k,q=0;
	for(int i=1;i<=k;i++) a[i]=i;
	for(int i=1;i<=k/n;i++){
		for(int j=1;j<=n;j++){
			front++;
			if(j==n) b[++q]=a[front];
			for(int t=1;t<=p;t++){
				front++;
				a[++tail]=a[front];
			} 
		}
	}
	sort(b+1,b+1+q);
	for(int i=1;i<=k/n;i++) cout<<b[i]<<endl;
	return 0; 
	
	
} 

 

3、连通块,这个还蛮有用的,手写队列

查找四个方向上有多少个连通块 map[n][n]、vis[n][n]、que[n][2]

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int n,m;
int map[101][101];
int dis[101][101];
int queue[10001][2]; 
int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
int ans;
void bfs(int x,int y){
	int head=1;
	int rear=2;//这是队列!!!这两个总的有 
	queue[1][0]=x;queue[1][1]=y;
	while(head<rear){
		x=queue[head][0];
		y=queue[head][1];
		head++;
		for(int i=0;i<4;i++){
		int x1=x+dir[i][0];
		int y1=y+dir[i][1];
		if(x1>0&&x1<=n&&y1>0&y1<=m&&map[x1][y1]&&!dis[x1][y1]){
			dis[x1][y1]=1;
			queue[rear][0]=x1;
			queue[rear++][1]=y1;//入队 
		}
	}
	} 
	
}
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	for(int j=1;j<=m;j++) cin>>map[i][j];
	memset(dis,0,sizeof(dis));
	for(int i=1;i<=n;i++)
	for(int j=1;j<=m;j++){
		if(map[i][j]&&!dis[i][j]){
			bfs(i,j);
			ans++;
		}
	}
	cout<<ans<<endl;
return 0;
}

4、围成面积

这道题计算被1围起来的0的个数,边缘都是0,这道题的想法就是!!把四周的0都变为1,最后枚举剩下的0,就相当于要从正方形的四条边去bfs

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
#include<cstdio>
using namespace std;
//这道题得思路很难想,从边缘开始搜索,标记没有被1包围的0使他们和 1 成为同样的节点,最后枚举剩余的0即可 
int map[20][20];
int queue[101][2];
int dis[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
void bfs(int x,int y){
	int head=1,tail=0;
	map[x][y]=-1;//使这些0变为-1 
	queue[head][0]=x;
	queue[head][1]=y;
	while(head!=tail){
		tail++;
		for(int i=0;i<4;i++){
			int nx=queue[tail][0]+dis[i][0];
			int ny=queue[tail][1]+dis[i][1];
			if(map[nx][ny]==-1) continue;
			else map[nx][ny]=-1;
 			head++;
			queue[head][0]=nx;
			queue[head][1]=ny; 
		}
		
	}
}
int main(){
	int ans=0;
	memset(map,255,sizeof(map));  //首先要先初始化map为-1 !!!!!(255=-1) //能够在搜索的时候退出 
	//所以map[0][i],map[i][0]等都是-1 
	for(int i=1;i<=10;i++)   //这里从1开始,是可以不用再bfs里面判断其下标合不合理 
	for(int j=1;j<=10;j++) {
		cin>>map[i][j];
		map[i][j]=-map[i][j];//注意这里的标记,既可以用来表示其代表的值,也可以用来表示有没有访问过 
	}//这里0还是0,1变为了-1 
	for(int i=1;i<=10;i++){
		if(!map[i][1]) bfs(i,1);
		if(!map[i][10]) bfs(i,10);
		if(!map[1][i]) bfs(1,i);
		if(!map[10][i]) bfs(10,i);//如果是0就开始搜索 
	}
	
	for(int i=1;i<=10;i++)
	for(int j=1;j<=10;j++) if(map[i][j]==0) ans++;//这个时候还有的0就是被包围的,因为从边缘搜索得到的0全部都被标记为了-1 
	cout<<ans<<endl;
return 0;
}

1360:奇怪的电梯(lift)

这里使用了一个多的数组sum[n]来保证最少的次数记录

pre[n]、num[n]、vis[n]、sum[n]

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
#include<cstdio>
using namespace std;
int pre[10001],aa[10001],vis[10001];
int sum[10001]; 
//pre表示当前的楼层(队列),aa表示能上升和下降的数量 
//vis表示是否经过(保证最小距离)sum表示所用的次数!!!!(useful) 
int n,a,b;
int main(){
	cin>>n>>a>>b;
	for(int i=1;i<=n;i++) cin>>aa[i];
	int head=0,tail=1;
	pre[tail]=a;
	memset(vis,0,sizeof(vis));
	vis[a]=1;//确保只能去一次 
	do{
		head++;
		for(int i=-1;i<=1;i+=2){//模拟上下两次选择 
			if(pre[head]+i*aa[pre[head]]>=1&&pre[head]+i*aa[pre[head]]<=n&&!vis[pre[head]+i*aa[pre[head]]]){
				tail++;
				pre[tail]=pre[head]+i*aa[pre[head]];
				vis[pre[head]+i*aa[pre[head]]]=1;
				sum[tail]=sum[head]+1;//这个数列的作用就相当于queue[n][3] //不能写为ans++ 
			}
		}
	}while(head<tail&&pre[head]!=b);//到达目标在这里判断 
	if(a==b) cout<<0<<endl;
	else if(pre[tail]==b) cout<<sum[tail]<<endl;
	else cout<<"-1"<<endl; 
return 0;
}

5、产生数,给定一个数n和k个变换规则,求一共有多少种变换结果,注意去重,永恒的vis数组

其实没什么很复杂的,就是一位一位的改数字,如果不是重复的就放进去,不断让每一位都得到改变,尝试所有的可能

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
#include<queue>
#include<cstdio>
using namespace std;
int n,k;
int be[16],af[16];
int vis[10001];
queue<int> qu;
int main(){
	cin>>n>>k;
	memset(vis,0,sizeof(vis));
	for(int i=1;i<=k;i++) cin>>be[i]>>af[i];
	qu.push(n);
	vis[n]=1;
	int sum=1;
	while(!qu.empty()){
		int x=qu.front(),y=qu.front();
		//cout<<qu.front()<<endl; 
		qu.pop();
		int mod=1;
		while(x>0){
			int temp=x%10;
			x/=10;
			for(int i=1;i<=k;i++){
				if(be[i]==temp){
					int yy=y+(af[i]-be[i])*mod;//因为是一位一位处理的 
					if(!vis[yy]){
						sum++;
						vis[yy]=1;
						qu.push(yy);
					}
				}
			}
			mod*=10; //记住这里的操作!斯国一! 
		}
	}
	cout<<sum<<endl;
return 0;
}

  

1362:家庭问题(family)

这个是并查集

#include<iostream>
#include<stdio.h>
#include<cmath>
#include<cstring> 
#include<queue>
using namespace std;
#define INF 1e9+10
int fa[201];
bool isroot[201];
int sum[201];
int n,k;
int findf(int x){
	int a=x;
	while(x!=fa[x]) x=fa[x];
	while(a!=fa[a]){
		int z=a;
		a=fa[a];
		fa[z]=x;
	}
	return x;
}
void uni(int x,int y){
	int faa=findf(x);
	int fab=findf(y);
	if(faa!=fab) fa[faa]=fab;
}
void inti(int n){
	for(int i=1;i<=n;i++){
		isroot[i]=0;
		fa[i]=i;
	}
}
int main(){
	cin>>n>>k;
	inti(n);
	int xx,yy;
	for(int i=1;i<=k;i++){
		cin>>xx>>yy;
		uni(xx,yy);
	}
	for(int i=1;i<=n;i++){
		isroot[findf(i)]=1;
		sum[findf(i)]++;
	}
	int ans=0,maxn=-1;
	for(int i=1;i<=n;i++){
		ans+=isroot[i];
		maxn=max(maxn,sum[i]);
	}
	cout<<ans<<" "<<maxn<<endl;
	return 0; 
	
	
} 

  

 posted on 2020-02-05 18:42  shirlybabyyy  阅读(333)  评论(0)    收藏  举报