KuangBin刷題專題一----簡單搜索

1、棋盤問題 【POJ - 1321 】

題意
dfs板子題在這裏插入圖片描述
代碼

//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
char  a[10][10];//記錄棋盤位置
int put[10];// 記錄一列是否已放棋子
int n, k;    //矩陣寬,放棋子數目
int plan, sum; //  方案數和棋子數

void dfs(int hang){
    if(k==sum){
        plan++;
        return;
    }
    if(hang>=n)//到最後一行
        return;
    for(int j=0;j<n;j++)
        if(put[j]==0&&a[hang][j]=='#'){//這列沒放棋子且可以放棋子
            put[j]=1;//標記
            sum++;
            dfs(hang+1);//繼續往下
            put[j]=0;//改回來方便下一行判斷
            sum--;
        }
    dfs(hang+1);
}
int main() {
    while(scanf("%d%d",&n,&k)&& n != -1 && k != -1) {
        plan=0;sum=0;
        for(int i=0;i<n;i++) scanf("%s",&a[i]);
        memset(put,0,sizeof(put));
        dfs(0);
        printf("%d\n",plan);
    }
    return 0;
}

2、Dungeon Master【POJ2251】

傳送門

題意概括:
三維地牢,#不能走,.能走,S起點,E終點,求最短路徑
bfs,難點:有六個方向;爲找到最短路徑,使用優先隊列,讓步數step小的先出隊。
代碼:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
#include<map>
using namespace std;
int sx,sy,sz;
int ex,ey,ez;
int a,b,c;
char mp[35][35][35];//記錄地圖
int vis[35][35][35];//標記是否走過
int base[6][3]= {{-1,0,0},{1,0,0},{0,-1,0},{0,1,0},{0,0,-1},{0,0,1}}; //六個方向

struct node {
    int  x,y,z;//位置
    int step;//步數
    friend bool operator<(node a,node b)
    //默認的優先隊列是從大到小,要讓步數小的先出來,即時間少,重載<
    {
        return a.step>b.step;//優先隊列,步數小的先訪問
    }
};
priority_queue<node>q;

void bfs() {
    node p;
    p.x=sx;p.y=sy;p.z=sz;p.step=0;//初始化
    vis[sx][sy][sz]=1;
    q.push(p);
    while(!q.empty()){
        node s=q.top();
        q.pop();
        if(s.x==ex&&s.y==ey&&s.z==ez){//到達終點
            printf("Escaped in %d minute(s).\n",s.step);
            return;
        }
        for(int i=0;i<6;i++){//六種走法
            int xx=s.x+base[i][0];
            int yy=s.y+base[i][1];
            int zz=s.z+base[i][2];
            if(mp[xx][yy][zz]!='#'&&xx>=0&&xx<a&&yy>=0&&yy<b&&zz>=0&&zz<c&&!vis[xx][yy][zz]){//能不能走
                node e;
                e.x=xx;e.y=yy;e.z=zz;
                e.step=s.step+1;//!!最後輸出的隊列最上面的node,確保它的step是最終的step,即每次在前一個點上加一
                vis[e.x][e.y][e.z]=1;
                q.push(e);
            }
        }
    }
     cout<<"Trapped!"<<endl;

}

int main() {
    while(cin>>a>>b>>c,a+b+c){
        for(int i=0;i<a;i++){
            for(int j=0;j<b;j++){
                cin>>mp[i][j];//一次輸入一行
                for(int k=0;k<c;k++){
                    if(mp[i][j][k]=='S'){
                        sx=i;sy=j;sz=k;
                    }
                    if(mp[i][j][k]=='E'){
                        ex=i;ey=j;ez=k;
                    }
                }
            }
        }
        memset(vis,0,sizeof(vis));//每次都要初始化
        bfs();
    }
}

推薦題解:
https://www.cnblogs.com/sky-stars/p/10963418.html

3、Catch That Cow 【POJ - 3278】

題意
有一個農民和一頭牛,他們在一個數軸上,牛在k位置保持不動,農戶開始時在n位置。設農戶當前在M位置,每次移動時有三種選擇:1.移動到M-1;2.移動到M+1位置;3.移動到M*2的位置。問最少移動多少次可以移動到牛所在的位置。

分析:BFS的板子題,用隊列。用廣搜來搜索這三個狀態,直到搜索到牛所在的位置
代碼

#include<iostream>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
#include<map>
#define maxn 100001
using namespace std;
int n,k;
queue<int> q;
bool vis[maxn];
int step[maxn];//記錄步數的數組

int bfs(int n,int k){
    int s,temp;
    q.push(n);
    vis[n]=1;
    while(!q.empty()){//重複使用時,用此初始化的
        s=q.front();
        q.pop();
        for(int i=0;i<3;i++){//三個方向搜索
            if(i==0)temp=s+1;
            else if(i==1)temp=s-1;
            else
                temp=s*2;
            if(temp>100000||temp<0)
                continue;//越界
            if(!vis[temp]){
                step[temp]=step[s]+1;
                if(temp==k)return step[temp];//到結束條件終止
                vis[temp]=1;//置爲訪問過
                q.push(temp);//temp元素放到隊列末端
            }
        }
    }
}

int main(){
    while(cin>>n>>k){
        memset(vis,0,sizeof(vis));
        if(n>=k)
            cout<<n-k<<endl;
        else
            cout<<bfs(n,k)<<endl;
    }
    return 0;
}

4、 迷宮問題 POJ - 3984

題目
思路:
跟前面第2題很像,要更爲簡單,都是bfs找到路徑,由於輸出的是路徑不是最短路步數,在結構體中定義stepx和stepy兩個數組記錄路徑。
需要注意的是前面第2題在push一個node前只要把step置爲前一個node的step+1,這裏需要繼承前一個node的stepx和stepy,所以直接開始是定義node e=s(見下代碼)。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=100010;
int vis[6][6];int a[6][6];
int mp[6][6];
int base[4][2]={{0,-1},{0,1},{-1,0},{1,0}};

struct node{
  int x,y;
  int stepx[30],stepy[30],cnt;
};

queue<node>q;
void bfs(){
  node p;
  p.x=0;p.y=0,p.cnt=0;
  // vis[0][0]=1;
  q.push(p);
  while(!q.empty()){
    node s=q.front(),tmp1;
    q.pop();
    if(s.x==4&&s.y==4){//到終點
      printf("(0, 0)\n");
      for(int i=0;i<s.cnt;++i)
        printf("(%d, %d)\n",s.stepx[i],s.stepy[i]);
      return;
    }
    //註釋的這段會稍微簡潔一些
    // tmp1=s;
    //     for(int i=0;i<4;++i)
    //     {
    //         tmp1.x=s.x+base[i][0];
    //         tmp1.y=s.y+base[i][1];
    //         if(tmp1.x>=0&&tmp1.x<=4&&tmp1.y>=0&&tmp1.y<=4&&!vis[tmp1.x][tmp1.y]&&a[tmp1.x][tmp1.y]==0)
    //         {
    //             vis[tmp1.x][tmp1.y]=1;
    //             tmp1.stepx[tmp1.cnt]=tmp1.x;
    //             tmp1.stepy[tmp1.cnt++]=tmp1.y;
    //             q.push(tmp1);
    //         }
    for(int i=0;i<4;i++){//四個方向
      int xx=s.x+base[i][0];
      int yy=s.y+base[i][1];
      if(a[xx][yy]==0&&xx>=0&&xx<5&&yy>=0&&yy<5&&!vis[xx][yy]){
        node e=s;//用中間變量結構體e來暫存,滿足要求則push,注意要先=s
        e.x=xx;e.y=yy;
        e.stepx[e.cnt]=e.x;
        e.stepy[e.cnt++]=e.y;//注意cnt++
        vis[e.x][e.y]=1;
        q.push(e);
      }
    }
  }
}
int main(){
  std::ios::sync_with_stdio(false);
  std::cin.tie(NULL);
  std::cout.tie(NULL);
  for(int i=0;i<5;i++){
    for(int j=0;j<5;j++){
      cin>>a[i][j];
    }
  }
  memset(vis,0,sizeof(vis));//初始化不能忘
  bfs();
  return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章