队列 2018-12-9

21 篇文章 0 订阅
2 篇文章 0 订阅

队列的特征是先进先出。
一般用f(first)表示队首,用l(last)表示队尾,然后进行操作
两种方法:
1.STL法:

#include <bits/stdc++.h>
using namespace std;
queue <int>	q;
int n;
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		q.push(i);
	while(!q.empty()){
		printf("%d ",q.front());
		q.pop();
	}
	return 0;
}

2.数组模拟队列

#include <bits/stdc++.h>
using namespace std;
const int maxn=10000+10;
int q[maxn],n,l,f;
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		q[++l]=i;
	while(f<l){
		f++;
		printf("%d ",q[f]);
	}
	return 0;
}

一些队列的运用:广搜
题意简述:
有一个n*m的迷宫,1为道路,0为墙,2为宝藏,从1,1开始,求出宝藏的坐标和最短的路径,找不到宝藏输出"404 NOT FOUND"。
1.用数组模拟队列
代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn=100+10;
int q[maxn*maxn][3],p[maxn][maxn],a[maxn][maxn],n,m,f,l;
int d[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			scanf("%d",&a[i][j]);
	l=1;
	q[1][0]=q[1][1]=1;
	p[1][1]=1;
	while(f<l){
		f++;
		int x=q[f][0],y=q[f][1];
		for(int i=0;i<4;i++){
			int xx=x+d[i][0],yy=y+d[i][1];
			if(a[xx][yy] && !p[xx][yy]){
				q[++l][0]=xx;
				q[l][1]=yy;
				q[l][2]=q[f][2]+1;
				p[xx][yy]=1;
				if(a[xx][yy]==2){
					printf("%d %d %d",xx,yy,q[l][2]);
					return 0;
				}
			}
		}
	}
	printf("404 NOT FOUND");
	return 0;
}

2.STL
代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn=100+10;
struct node{
	int x,y,s;
};
queue <node> q;
int p[maxn][maxn],a[maxn][maxn],n,m;
int d[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			scanf("%d",&a[i][j]);
	node tmp;
	tmp.x=1;
	tmp.y=1;
	tmp.s=0;
	q.push(tmp);
	p[1][1]=1;
	while(!q.empty()){
		tmp=q.front();
		for(int i=0;i<4;i++){
			int xx=tmp.x+d[i][0],yy=tmp.y+d[i][1];
			if(a[xx][yy] && !p[xx][yy]){
				node t;
				t.x=xx;
				t.y=yy;
				t.s=tmp.s+1;
				q.push(t);
				p[xx][yy]=1;
				if(a[xx][yy]==2){
					printf("%d %d %d",xx,yy,t.s);
					return 0;
				}
			}
		}
		q.pop();
	}
	printf("404 NOT FOUND");
	return 0;
}

看到这一题
这一题可以用三种方法做:
1.广搜法:

#include <iostream>//坑人的POJ,不能用万能头文件
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn=100+5,maxm=10000+10;
int n,m,s,t,ans,a[maxn][maxn],q[maxm][2],d[9][2]={{1,1},{1,0},{1,-1},{0,-1},{0,1},{-1,0},{-1,1},{-1,-1}};//初始化定义坐标数组
char c;//一个字母
int main(){	
    cin>>n>>m;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++){//输入,如果是"W"就代表有水,设为1,否则就设为0。和上一题一样,这种操作同样潜移默化地将四周设置了一层无形的屏障,如果超过n行m列,就都是0,走无可走。
			cin>>c;
			a[i][j]=c=='W'?1:0;//三目,也可以如下写:
			/*
			if(c=='W')
			   a[i][j]=1;
			else
			   a[i][j]=0;
			*/
		}
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			if(a[i][j]){//如果a[i][j]还没有被灌水,那就灌水吧!!!
			    ans++;//计数器(存储找到的湖泊总数)
			    a[i][j]=0;//设为已经走过
			    q[1][1]=j;//坐标初始化
			    q[1][0]=i;
			    s=0;//队列首尾初始化
			    t=1;
			    while(s<t){//如果首<尾,BFS
				    s++;//首加一
				    for(int k=0;k<8;k++){//向四周的8个方向扩展灌水
					    int xx=q[s][0]+d[k][0];//存储当前的x坐标和y坐标
					    int yy=q[s][1]+d[k][1];
					    if(a[xx][yy]){//如果没有灌过,就继续灌
						    q[++t][0]=xx;//同样存下新一轮坐标
						    q[t][1]=yy;
					        a[xx][yy]=0;//设为已经灌过水了
					        //和上一题不同的是,这里不需要输出步骤,只需要算出湖泊总数即可,那么也就不需要多定义一个小的单元数组
					    }
				    }
			    }
		    }
	cout<<ans;//输出
	return 0;//一个好的程序猿评判标准
}

深搜法

#include <iostream>
#include <cstdio>
using namespace std;
const int maxn=100+10;
int a[maxn][maxn];
void find(int x,int y){
	a[x][y]=0;
	if(a[x+1][y])
	   find(x+1,y);
	if(a[x-1][y])
	   find(x-1,y);
	if(a[x][y+1])
	   find(x,y+1);
	if(a[x][y-1])
	   find(x,y-1);
	if(a[x+1][y-1])
	   find(x+1,y-1);
	if(a[x+1][y+1])
	   find(x+1,y+1);
	if(a[x-1][y+1])
	   find(x-1,y+1);
	if(a[x-1][y-1])
	   find(x-1,y-1);
}
int main(){
	int n,m;
	cin>>n>>m;
	getchar();
	char c;
	for(int i=1;i<=n;i++)
	    for(int j=1;j<=m;j++){
	    	cin>>c;
	    	a[i][j]=c=='.'?0:1;
	    }
	int ans=0;
	for(int i=1;i<=n;i++)
	    for(int j=1;j<=m;j++)
	        if(a[i][j]){
	        	ans++;
	            find(i,j);
	        }
	cout<<ans;
	return 0;
}

这一题
SPFA(不用链式前向星):

#include <bits/stdc++.h>
using namespace std;
const int maxn=10000+105,inf=2147483647;
struct node{
	int to,z;
};
int p[maxn],d[maxn],n,m,s,x,y,z,f,l;
vector<node>e[maxn];
int q[maxn*105];
int main(){
	scanf("%d%d%d",&n,&m,&s);
	for(int i=1;i<=m;i++){
		scanf("%d%d%d",&x,&y,&z);
		node t;
		t.to=y;
		t.z=z;
		e[x].push_back(t);
	}
	for(int i=1;i<=n;i++)
		d[i]=inf;
	d[s]=0;
	q[1]=s;
	p[s]=1;
	l=1;
	while(f<l){
		f++;
		int x=q[f];
		for(int i=0;i<e[x].size();i++){
			int u=e[x][i].to,v=e[x][i].z;
			if(d[u]>d[x]+v){
				d[u]=d[x]+v;
				if(!p[u]){
					q[++l]=u;
					p[u]=1;
				}
			}
		}	
		p[x]=0;
	}
	for(int i=1;i<=n;i++)
		if(d[i]<inf)
			printf("%d ",d[i]);
		else
			printf("2147483647 ");
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值