bfs模版题
题目1:Catch That Cow
题意:直线上从n点移动到k点需要多少时间,共有3中移动方式(假设当前位置是x):
1.移动到左边(x-1)
2.移动到右边(x+1)
3.移动到2*x
每种移动所需的时间都是1分钟。
思路:bfs搜索,从每一个当前状态x最多都可以扩展出三个状态:x-1 、x+1、2*x,当bfs到终点k的时候结束。
代码:
#include<iostream>
#include<queue>
#include<cstdio>
#include<cmath>
#include<vector>
#include<cstring>
#define ll long long
using namespace std;
const int M=1e5+100,fin=1e8;
int a[M];
void bfs(int n,int k)
{
int c;
fill(a,a+M,fin);
queue<int> q;
q.push(n);
q.push(0);
while(!q.empty())
{
n=q.front();
q.pop();
c=q.front();
q.pop();
if(c>=a[n])continue;
a[n]=c;
for(int i=-1; i<=1; i+=2)
if(0<=(i+n)&&(i+n)<=M)
{
q.push(i+n);
q.push(c+1);
}
if(0<=(2*n)&&(2*n)<=M)
{
q.push(2*n);
q.push(c+1);
}
}
}
int main()
{
int n,k;
scanf("%d%d",&n,&k);
bfs(n,k);
printf("%d\n",a[k]);
return 0;
}
题目2
思路:使用bfs进行搜索,从当前点最多可以扩展出4个点(4个方向),某个点可能会多次被扩展到,取其中最小的即可。
代码:
#include<iostream>
#include<queue>
#include<cstdio>
#include<cmath>
#include<vector>
#include<cstring>
#define ll long long
using namespace std;
const int M=120,fin=1e8;
int a[M][M],n,v[M][M],dir[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
bool in(int x,int y)
{
if(1<=x&&x<=n&&1<=y&&y<=n)return true;
else return false;
}
int bfs(int x,int y)
{
int st;
for(int i=1;i<=n;i++)fill(v[i]+1,v[i]+n+1,fin);
queue<int> q;
q.push(x);
q.push(y);
q.push(a[x][y]);
while(!q.empty())
{
x=q.front();q.pop();
y=q.front();q.pop();
st=q.front();q.pop();
if(st>=v[x][y])continue;
v[x][y]=st;
for(int i=0;i<4;i++)
{
int tx=x+dir[i][0],ty=y+dir[i][1];
if(a[tx][ty]&&in(tx,ty))
{
q.push(tx);
q.push(ty);
q.push(st+a[tx][ty]);
}
}
}
return v[n][n];
}
int main()
{
while(scanf("%d",&n)==1)
{
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%d",&a[i][j]);
printf("min=%d\n",bfs(1,1));
}
return 0;
}
使用bfs来求最值小值的时候,如果第一次到达某一点的答案就是最小值(也就是说以后到达该点的值都比第一次大)那么就可以用例题1中的模版,当从队列中出来的点就是终点的时候就可以返回了。
但如果第一次到达某一点的值不一定是最小值的话,就不能用例题1中的模版,应该使用例题2中的模版,即用bfs搜索所有的可能结果,从中取最优值。当搜索到某一点的时候判断这一次的值是否比上一次的值更优,如果更优才会扩展他后面的点,否则忽略(剪枝)。初始值为最大值。
其实第二种方法就已经包括了第一中方法,但是效率没有第一种高。