搜索专题

搜索专题

标签(空格分隔): 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\n",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\n");
}

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;
}
  1. 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)\n");
            break;
        case 1:
            printf("FILL(2)\n");
            break;
        case 2:
            printf("POUR(1,2)\n");
            break;
        case 3:
            printf("POUR(2,1)\n");
            break;
        case 4:
            printf("DROP(1)\n");
            break;
        case 5:
            printf("DROP(2)\n");
            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);
    }
}

原文地址:https://www.cnblogs.com/yxmqaq/p/9800788.html

时间: 2024-10-28 14:50:45

搜索专题的相关文章

搜索专题小结及例题:POJ2251&amp;POJ1426&amp;POJ3087&amp;POJ2488

图的遍历也称为搜索,就是从图中某个顶点出发,沿着一些边遍历图中所有的顶点,且每个顶点仅被访问一次,遍历可采取两种不同的方式:深度优先搜索(DFS)和广度优先搜索(BFS). 1.DFS算法思想` 从顶点v出发深度遍历图G的算法 ① 访问v0顶点,置vis[v0]=1,搜索v0未被访问的邻接点w,若存在邻接点w,则dfs(w),直到到达所有邻接点都被访问过的顶点u为止,接着退回一步,看是否还有其他没有被访问的邻接点.如果有,则访问此顶点,进行前述类似的访问,如果没有,就在退回一步进行搜索,重复上述

搜索专题总结

搜索专题总结 第七章的例题做得差不多了,还有一道枚举二叉树和一道比较难的搜方块的没过,另外有一道火柴的用IDA*水过,并没有过大数据,由于这道可以用dancing links过,所以留着dancing links一坑.接下来总结下这章的收获,首先最重要的当然是不需要判重的高效率的IDA*以及估价函数的设计技巧:然后是bfs+hash写得更熟练了,如果hash需要erase那么就只能用指针版的,但是效率会很慢,否则就用数组版的. 做搜索题的几个要点: 1,估算最坏复杂度. 2,寻找合适的剪枝策略,

CSP2019突击训练(搜索专题)

专题一 简单搜索POJ 1321 棋盘问题POJ 2251 Dungeon MasterPOJ 3278 Catch That CowPOJ 3279 FliptilePOJ 1426 Find The MultiplePOJ 3126 Prime PathPOJ 3087 Shuffle'm UpPOJ 3414 PotsFZU 2150 Fire GameUVA 11624 Fire!POJ 3984 迷宫问题HDU 1241 Oil DepositsHDU 1495 非常可乐HDU 261

‘简单’搜索专题总结

kuangbin专题一 A. 棋盘问题 在是棋盘的格子上放置棋子,其中要求所有棋子不同行也不同列,求摆放的方案数. dfs,参数:行.棋子数,遍历的时候要回溯. B. Dungeon Master 走迷宫,3D的走迷宫. C. Catch That Cow 最短时间找到那只牛. bfs,剪枝. D. FilpTile 翻方块,上一行状态决定下一行的翻转. E. Find The Multiple 大胆的bfs,数据范围很小的. F. Prime Path bfs G. Shuffle'm Up

记忆化搜索专题

Hdoj  1078 题目足迹 题意: n*n的矩阵,从(0,0)出发,每个点上有一个数值,每次只能水平或竖直的走至多k个格子,要求总的路线上的数值是严格单增的,并且使总的和最大. 代码: 1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 #define mem(a,b) memset(a,b,sizeof(a)) 6 #define for

搜索专题小结:迭代加深搜索

迭代加深搜索 迭代加深搜索(Iterative Deepening Depth-First Search, IDDFS)经常用于理论上解答树深度上没有上界的问题,这类问题通常要求出满足某些条件时的解即可.比如在"埃及分数"问题中要求将一个分数a/b分解成为若干个形如1/d的加数之和,而且加数越少越好,如果加数个数相同,那么最小的分数越大越好.下面总结一下该方法的一般流程: (1)概述:迭代加深搜索是通过限制每次dfs的最大深度进行的搜索.令maxd表示最大的搜索深度,那么dfs就只能在

poj 3126 Prime Path(搜索专题)

Prime Path Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 20237   Accepted: 11282 Description The ministers of the cabinet were quite upset by the message from the Chief of Security stating that they would all have to change the four-di

搜索专题(不定期更新)

1.POJ 2386  Lake Counting 题意:给出一块区域,询问有多少个湖泊? 思路:DFS,对于'W',深搜一次,并标记已访问.之后每次对未访问的'W'做一次深搜. 1 #include<iostream> 2 #include<memory.h> 3 using namespace std; 4 char lake[105][105]; 5 bool vis[105][105]; 6 int n, m; 7 void DFS(int r, int c) 8 { 9

暴力搜索专题小结:全排列及可重集排列生成算法

1~n的全排列 (1)思路:按照递归的思想,初始化集合S中含有1~n所有元素.如果1~n的集合S为空,那么输出全排列:否则从小到大依次考虑每个元素i,在A的末尾添加i后,集合S变为S-{i}.这里我们不需要集合S,只需要利用一个变量cur表示当前位要填的数即可.那么A中没有出现过的元素均可以选择. #define N 100 int A[N]; void print_permutation(int n, int*A, int cur) { if (cur == n) { for (int i =