搜索专题
Posted yxmqaq
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了搜索专题相关的知识,希望对你有一定的参考价值。
搜索专题
标签(空格分隔): ACM专题小结
- 搜索专题主要就是围绕dfs()和bfs().
- 这两个函数其实不难,搜索可以解决很多最小路径,最少次数问题bfs()等问题
- 维数从
一维到三维
;主要抓住移动的方向的控制
,以及对访问过的状态的标记,以免重复访问,重复访问一方面运行时间加长另一方面申请的空间也会无厘头的暴增。
- 曾经在刷一道题的时候,系统显示的使用空间远远大于定义变量的空间,一时间懵逼了,后来才发现是
标记
没处理好,导致了大量的重复访问。 - 还有一个要注意的地方就是
队列的清空
,或者在函数里面定义队列,每次调用函数的时候重新申请空间。或者定义为全局队列,可以减少内存使用,但是一定要记得清空,曾经为此wa了一天
下面给出模板:
方向控制:
int dx[][2]={{0,1},{0,-1},{1,0},{-1,0},{1,1},{1,-1},{-1,-1},{-1,1}};//0-7二维方向的控制
int to[6][3] = {{0,0,1},{0,0,-1},{0,1,0},{0,-1,0},{1,0,0},{-1,0,0}};//三维方向的控制
标记:
bool vis[][][]//对应维数
或者:int step[][][];对应维数
初始化memset(step,-1,sizeof(step));//只要不为-1即为之前出现过的状态。
bfs里面的最短次数之类的可以使用struct或者另外定义int step[][][]
int bfs(){
memset(vis,0,sizeof(vis));//切记要初始化标记!!!
node tp=a;
vis[a]=1;
tp.step=0;
queue<int> que;//定义为局部队列,可以不用清空。!!!
que.push(tp);
node tmp;//用与临时存放tp的改变值
while(!que.empty(){
tp.que.front();que.pop();
if(tp==终止条件)return tp.step;
for(int i=0;i<n;i++){//n为下一步的状态数
tmp.x=tp.x+dx[i];
tmp.y=tp.y+dy[i];
if(tmp符合条件&&vis[][][]==0){注意使用未标记的状态
tmp.step=tp.step+1;
que.push(tmp);
}
}
int dx[][2]={{0,1},{0,-1},{1,0},{-1,0},{1,1},{1,-1},{-1,-1},{-1,1}};//0-7方向控制
void dfs(int x,int y){
s[x][y]=‘*‘;
int tx,ty;
for(int i=0;i<8;i++){
tx=x+dx[i][0],ty=y+dx[i][1];
if(tx>=0&&tx<n&&ty>=0&&ty<m&&s[tx][ty]==‘@‘){
dfs(tx,ty);
}
}
}
int main(){
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(s[i][j]==‘@‘) {
ans++;
fs(i, j);
}
}
}
}
附上一些题:
1.非常可乐(倒水问题):
#include<cstdio>
#include<cstring>
#include<queue>
#include <iostream>
using namespace std;
int v[5];
int sign[110][110][100];
struct cup
{
int v[5];
int step;
}temp;
void pour(int a,int b)//模拟倒水过程
{
int sum=temp.v[a]+temp.v[b];
if(sum>=v[b])
temp.v[b]=v[b];
else
temp.v[b]=sum;
temp.v[a]=sum-temp.v[b];
}
void bfs()
{
int i,j;
queue<cup>q;
cup cnt;
cnt.v[1]=v[1];
cnt.v[2]=0;
cnt.v[3]=0;
cnt.step=0;
q.push(cnt);
memset(sign,0,sizeof(sign));
sign[v[1]][0][0]=1;
while(!q.empty())
{
cnt=q.front();
q.pop();
if(cnt.v[1]==cnt.v[3]&&cnt.v[2]==0)
{
printf("%d
",cnt.step);
return ;
}
for(i=1;i<4;++i)
{
for(j=1;j<4;++j)
{
if(i!=j)
{
temp=cnt;
pour(i,j);
if(!sign[temp.v[1]][temp.v[2]][temp.v[3]])
{
temp.step++;
q.push(temp);
sign[temp.v[1]][temp.v[2]][temp.v[3]]=1;
}
}
}
}
}
printf("NO
");
}
int main()
{
while(scanf("%d%d%d",&v[1],&v[2],&v[3])&&v[1]||v[2]||v[3])
{
if(v[2]>v[3])
{
int t=v[2];
v[2]=v[3];
v[3]=t;
}
if(v[1]%2==0)
bfs();
else cout<<"NO"<<endl;
}
return 0;
}
2.Dungeon Master (三维bfs()):
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
int MAX=(1<<30);
struct node{
int x,y,z;
int step;
node(){
step=MAX;
}
};
char map[34][34][34];
int c,l,r;
int ex,ey,ez,sx,sy,sz;//记录起点终点
int to[6][3] = {{0,0,1},{0,0,-1},{0,1,0},{0,-1,0},{1,0,0},{-1,0,0}};
bool vis[34][34][34];
int bfs(){
queue<node> que;
node tmp,tp;
tmp.x=sx,tmp.y=sy,tmp.z=sz;tmp.step=0;
vis[sx][sy][sz]=1;
que.push(tmp);
while(que.size()){
tp=que.front(),que.pop();
if(tp.x==ex&&tp.y==ey&&tp.z==ez){
return tp.step;
}
for(int i=0;i<6;i++){
tmp.x=tp.x+to[i][0];
tmp.y=tp.y+to[i][1];
tmp.z=tp.z+to[i][2];
if(tmp.x<0||tmp.x>=l||tmp.y<0||tmp.y>=r||tmp.z<0||tmp.z>=c||vis[tmp.x][tmp.y][tmp.z]||map[tmp.x][tmp.y][tmp.z]==‘#‘)
continue;
vis[tmp.x][tmp.y][tmp.z]=1;
tmp.step=tp.step+1;
que.push(tmp);
}
}
return MAX;
}
int main(){
char ch;
//cout<<MAX;
while(cin>>l>>r>>c&&(l+c+r)){
memset(vis,0,sizeof(vis));
getchar();
for(int i=0;i<l;i++){ /// l ,r,c,x ,y,z
for(int j=0;j<r;j++){
for(int k=0;k<c;k++){
ch=getchar();
map[i][j][k]=ch;
if(ch==‘S‘){
sx=i,sy=j,sz=k;
}
if(ch==‘E‘){
ex=i,ey=j,ez=k;
}
}
getchar();
}
getchar();
}
int ans=bfs();
if(ans==MAX){
cout<<"Trapped!"<<endl;
}
else{
cout<<"Escaped in "<<ans<<" minute(s)."<<endl;
}
}
return 0;
}
- Pots /迷宫问题 (要求记录路径的问题)
//pots
#include <iostream>
#include <cstdio>
using namespace std;
#include <cstring>
#include <queue>
struct node {
int x,y;
string s;//记录操作步骤对应的数字
};
int step[105][105];
int a,b,c;
void done(int i)//亮点,巧妙的把路径与数字建立联系!!!
{
switch(i) {
case 0:
printf("FILL(1)
");
break;
case 1:
printf("FILL(2)
");
break;
case 2:
printf("POUR(1,2)
");
break;
case 3:
printf("POUR(2,1)
");
break;
case 4:
printf("DROP(1)
");
break;
case 5:
printf("DROP(2)
");
break;
}
}
void bfs()
{
char ch;
int i,j;
queue<node >q;
node tp,tmp;
tp.x=0,tp.y=0;
step[0][0]=0;
q.push(tp);
while(!q.empty()) {
tp=q.front();
q.pop();
if(tp.x==c||tp.y==c) {
cout<<step[tp.x][tp.y]<<endl;
for(int j=0; j<tp.s.size(); j++) {
done(tp.s[j]-‘0‘);
}
return;
}
for(i=0; i<6; i++) {
if(i==0) {
tmp.x=a;
tmp.y=tp.y;
}
if(i==1) {
tmp.x=tp.x;
tmp.y=b;
}
if(i==2) {
tmp.y = tp.x + tp.y;
if(tmp.y>=b) {
tmp.x=tmp.y-b;
tmp.y=b;
} else
tmp.x=0;
}
if(i==3) {
tmp.x=tp.y+tp.x;
if(tmp.x>=a) {
tmp.y=tmp.x-a;
tmp.x=a;
} else
tmp.y=0;
}
if(i==4) {
tmp.x=0;
tmp.y=tp.y;
}
if (i==5) {
tmp.x=tp.x;
tmp.y=0;
}
if(step[tmp.x][tmp.y]==-1) {
step[tmp.x][tmp.y]=step[tp.x][tp.y]+1;
ch=‘0‘+i;
tmp.s=tp.s+ch;
q.push(tmp);
}
}
}
cout<<"impossible"<<endl;
}
int main()
{
while(~scanf("%d%d%d",&a,&b,&c)) {
memset(step,-1,sizeof(step));
bfs();
}
return 0;
}
//迷宫问题:
#include <iostream>
#include <stack>
#include <queue>
using namespace std;
struct node{
int data;
int x,y;//记录当前点的坐标
int px,py;//prex,prey记录前一个点的坐标
//bool f=0;
void set(int i,int j){
x=i;y=j;
}
node(){
px=py=-1;
}
}dex[6][6];
queue<node> que;
stack<node> st;
node tmp;
int dx[]={0,0,1,-1};
int dy[]={1,-1,0,0};
bool f[6][6];
void bfs(node x){
que.push(x);
while(que.size()){
tmp=que.front();
//tmp.f=1;
f[tmp.x][tmp.y]=1;
que.pop();
for(int i=0;i<4;i++){
if(f[tmp.x+dx[i]][tmp.y+dy[i]]==0&&dex[tmp.x+dx[i]][tmp.y+dy[i]].data==0&&tmp.x+dx[i]>=0&&tmp.x+dx[i]<5&&tmp.y+dy[i]>=0&&tmp.y+dy[i]<5){
dex[tmp.x+dx[i]][tmp.y+dy[i]].px=tmp.x;
dex[tmp.x+dx[i]][tmp.y+dy[i]].py=tmp.y;
que.push(dex[tmp.x+dx[i]][tmp.y+dy[i]]);
if(tmp.x+dx[i]==4&&tmp.y+dy[i]==4)return;
}
}
}
}
int main(){
int n=5;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
cin>>dex[i][j].data;
dex[i][j].set(i,j);
}
}
bfs(dex[0][0]);
st.push(dex[4][4]);
node tmp1;
while(1){
tmp1=st.top();
if(tmp1.px+tmp1.py==-2)break;
st.push(dex[tmp1.px][tmp1.py]);
}
while(st.size()){//找到终点之后沿着px,py找前一个点,直到到起点则为完整路径。
tmp1=st.top();
cout<<"("<<tmp1.x<<", "<<tmp1.y<<")"<<endl;
st.pop();
}
return 0;
}
//找只由0,1构成的数字:
void bfs()
{
que.push(1);
while(!que.empty())
{
long long tmp = que.front();
que.pop();
if (tmp % n == 0) {ans=tmp;return;}
que.push(tmp * 10);
//每一个数的下一状态只有两个,a*10,a*10+1;
que.push(tmp * 10 + 1);
}
}
以上是关于搜索专题的主要内容,如果未能解决你的问题,请参考以下文章