BFS基础入门

广度优先搜索是用队列来实现的,一般来解决查找最短路径的,它是从一个点 广着向外搜索,最先搜到终点的那一条路就是最短的路径了,如果题目要求输出这条路径,在搜索的过程中也可以用一个数组来记录路径。然后最后把路径输出来。刚学习BFS的时候因为还不大懂思想,似懂非懂,代码就是凭印象写的,所以经常写不出来,或者做另外一种形式的BFS题目就想不出来了,现在还算稍微理解了些,写出来加深下自己的理解。

先贴一题我第一次写的BFS吧,这题很基础,也就是一个找迷宫最短路的问题,在数据结构中也学习了图的遍历方法里面有个广度优先搜索,但是看书看的云里雾里还是多写几道题掌握的更好一些。

这道题POJ 3984 应该算是BFS中的基础入门题啦。

定义一个二维数组: 

int maze[5][5] = {
0, 1, 0, 0, 0,
0, 1, 0, 1, 0,
0, 0, 0, 0, 0,
0, 1, 1, 1, 0,
0, 0, 0, 1, 0,
};

它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或竖着走,不能斜着走,要求编程序找出从左上角到右下角的最短路线。
 
Input
一个5 × 5的二维数组,表示一个迷宫。数据保证有唯一解。
 
Output
左上角到右下角的最短路径,格式如样例所示。 (逗号后面有一个空格。。。 我成功贡献了一次PE)
 
SampleInput
0 1 0 0 0
0 1 0 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0
SampleOutput
(0, 0)
(1, 0)
(2, 0)
(2, 1)
(2, 2)
(2, 3)
(2, 4)
(3, 4)
(4, 4)

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<queue>
 4 using namespace std;
 5 int a[10][10];
 6 int vis[10][10];
 7 int mov[4][2]={
 8     1,0,
 9     -1,0,
10     0,-1,
11     0,1,
12        };///代表往4个方向都可以走,上下左右
13 
14 struct node///定义结构体来表示x y坐标
15 {
16     int x;
17     int y;
18 }pre[10][10],way[100];
19 queue<node>que;///STL定义队列
20 int check(int x,int y)
21 {
22     if(x<1||x>5||y<1||y>5)
23         return 0;
24     return 1;
25 }
26 void bfs()
27 {
28     node arr;
29     arr.x=1;///由于起点是(1,1)
30     arr.y=1;
31     que.push(arr);///将第一个点放进队列
32     vis[1][1]=1;
33     while(!que.empty())///当队列不是空的时候
34     {
35         node now;
36         now=que.front();
37         que.pop();///弹出来
38         if(now.x==5&&now.y==5)///如果广搜到(5,5)的话就return 并输出路径
39         {
40             int top=0;
41             while(1)
42             {
43                 way[top++]=now;///记录路径的way数组
44                 if(now.x==1&&now.y==1)///往前找 找到起点就退出
45                     break;
46                 now=pre[now.x][now.y];
47             }
48             while(top--)
49             {
50                 printf("(%d, %d)\n",way[top].x-1,way[top].y-1);///输出路径
51             }
52             return ;
53         }
54         for(int i=0;i<4;i++)
55         {
56             node temp;///用temp代表下一步要走的地方
57             temp.x=now.x+mov[i][0];
58             temp.y=now.y+mov[i][1];
59             if(check(temp.x,temp.y)==1&&vis[temp.x][temp.y]==0&&a[temp.x][temp.y]==0)///如果这个点没越界 并且没被走过 并且可以走
60             {
61                 vis[temp.x][temp.y]=1;///标记这个点被走过
62                 que.push(temp);///可以走这个点 入队
63                 pre[temp.x][temp.y]=now;///记录路径 temp的前一个是now
64             }
65         }
66     }
67 }
68 int main()
69 {
70     for(int i=1; i<=5; i++)
71     {
72         for(int j=1; j<=5; j++)
73         {
74             scanf("%d",&a[i][j]);
75         }
76     }
77     bfs();
78 }

这道题基本上就是广搜的思想了,把第一个点入队,然后把满足每个条件的继续入队,比如这题是满足往上下左右走的都入队,也就是继续搜索,直到队空退出或者满足了条件退出,满足的什么条件后会退出,写在if()中。

 

有的广搜的题目不是这种找路径的 比如其他的倒水问题之类的,做法也差不多,就是用一个for把每次可以满足的都入队,这才叫做广度搜索嘛,贴一题叫做质数大臣的题目POJ 3126

 

Problem Description

大臣们对保安局长的消息感到非常不安,因此他们不得不改变办公室的四位数房间号码。

时不时地改变房间号,是一个重要的安全问题。这能使得敌人无从下手。
- 但是你也知道,我选择了1033号码是有原因的。我是Prime minister(注:意译:总理,直译:质数大臣 其实是个冷笑话),你知道!
- 我知道所以你的新号码8179也是一个质数。你只需要在你办公室的门上粘贴四个新的数字。
- 不,不是那么简单。当我把第一个数字改成了8时,那么这个数字就会变成8033,这不是一个质数
- 我知道,作为Prime minister,你无法忍受在你家门口有一个非质数,甚至几秒钟。
- 对!所以我必须发明一个从1033到8179的质数路径,从一个质数到下一个质数,每次只有一位数字能发生变化。
现在,在一旁偷听的财政部长介入了。
- 请节省没有不必要的开支!我碰巧知道改变一个数字的价格是一磅。
- 嗯,在这种情况下,我需要一个计算机程序来降低成本。你是否知道一些非常便宜的编程大师?
- 实际我已经在做了。你看,有这个编程比赛正在进行...帮助Prime minister找到任何两个给定的四位数的质数之间最便宜的质数路径!当然,第一位数字必须是非零。在上面的情况下,这里有一个解决方案。

 

1033 
1733 
3733 
3739 
3779 
8779 
8179

这个解决方案的成本是6磅。 请注意,步骤2中粘贴的数字1在最后一步不能重复使用 - 必须购买新的1。

Input

第一行有一个正整数,代表测试数据的数量

对于接下来每一个测试数据,每行有两个数字,且两个数字都是四位质数(没有前导零)。

 

Output

对于每个测试数据输出一个整数,代表最小的花费,或者输出Impossible

SampleInput
3
1033 8179
1373 8017
1033 1033
SampleOutput
6
7
0

这道题目就不是找路径的但是求最少改变次数,所以也用广搜来做,每次改变4种,个十百千位都可以改变,由于一满足条件就return 所以第一个碰到满足条件的一定是最短的那一个,贴一下代码。

  1 #include<vector>
  2 #include<stdio.h>
  3 #include<algorithm>
  4 #include<math.h>
  5 #include<queue>
  6 #include<string.h>
  7 using namespace std;
  8 const int maxn=1e5+5;
  9 int vis[maxn],prime[maxn];
 10 int visit[maxn];
 11 int way[maxn];
 12 int pre[maxn];
 13 int flag=0;
 14 queue<int>que;
 15 void is_prime()
 16 {
 17     int top,n;
 18     top=0;
 19     long long i,j;
 20     for(i=2; i<maxn; i++)
 21     {
 22         if(vis[i]==0)
 23         {
 24             prime[top++]=i;
 25         }
 26         for(j=0; j<top&&i*prime[j]<maxn; j++)
 27         {
 28             vis[prime[j]*i]=1;///素数为0
 29             if(i%prime[j]==0)
 30                 break;
 31         }
 32     }
 33 }
 34 void init()
 35 {
 36     memset(visit,0,sizeof(visit));
 37     memset(pre,0,sizeof(pre));
 38     memset(way,0,sizeof(way));
 39     while(!que.empty())
 40     {
 41         que.pop();
 42     }
 43     flag=0;
 44 }
 45 void bfs(int x,int y)
 46 {
 47     que.push(x);
 48     while(!que.empty())
 49     {
 50         int q=que.front();///1033
 51         que.pop();
 52         if(q==y)
 53         {
 54             int top=0;
 55             while(1)
 56             {
 57                 way[top++]=q;
 58                 if(q==x)
 59                     break;
 60                 q=pre[q];
 61             }
 62             /* while(top--)
 63              {
 64                  printf("%d\n",way[top]);
 65              }*/
 66             printf("%d\n",top-1);
 67             flag=1;
 68             return ;
 69         }
 70         int a,b,c,d,s,temp;
 71         temp=q;
 72         d=temp%10;///3
 73         temp=temp/10;//103
 74         c=temp%10;///3
 75         temp=temp/10;//10
 76         b=temp%10;///0
 77         temp=temp/10;//1
 78         a=temp%10;///1
 79         //printf("%d %d %d %d\n",a,b,c,d);
 80         for(int i=1; i<10; i+=2) ///变个位(奇数才有可能)
 81         {
 82             s=a*1000+b*100+c*10+i;
 83             if(visit[s]==0&&s!=q&&vis[s]==0)///如果这个数字没有找过并且这个数字不是自己的话 而且是素数
 84             {
 85                 visit[s]=1;
 86                 pre[s]=q;
 87                 que.push(s);
 88             }
 89         }
 90         for(int i=0; i<10; i++) ///变十位
 91         {
 92             s=a*1000+b*100+i*10+d;
 93             if(visit[s]==0&&s!=q&&vis[s]==0)///如果这个数字没有找过并且这个数字不是自己的话 而且是素数
 94             {
 95                 visit[s]=1;
 96                 pre[s]=q;
 97                 que.push(s);
 98             }
 99         }
100         for(int i=0; i<10; i++) ///变百位
101         {
102             s=a*1000+i*100+c*10+d;
103             if(visit[s]==0&&s!=q&&vis[s]==0)///如果这个数字没有找过并且这个数字不是自己的话 而且是素数
104             {
105                 visit[s]=1;
106                 pre[s]=q;
107                 que.push(s);
108             }
109         }
110         for(int i=1; i<10; i++) ///变千位(从1开始没有前导0)
111         {
112             s=i*1000+b*100+c*10+d;
113             if(visit[s]==0&&s!=q&&vis[s]==0)///如果这个数字没有找过并且这个数字不是自己的话 而且是素数
114             {
115                 visit[s]=1;
116                 pre[s]=q;
117                 que.push(s);
118             }
119         }
120     }
121 }
122 int main()
123 {
124     int x,y,t;
125     is_prime();
126     scanf("%d",&t);
127     while(t--)
128     {
129         init();
130         scanf("%d %d",&x,&y);
131         bfs(x,y);
132         if(flag==0)
133         {
134             puts("Impossible");
135         }
136     }
137 }

 

我目前遇到的几种关于广搜的入门问题就在这啦,其实思想就是那样的,多写写应该就会了,接下来还有搜索进阶还要学呢,不过基础打好是最重要的!

posted @ 2018-08-01 21:21  star_fish  阅读(660)  评论(0编辑  收藏  举报