bfs dfs

图论

DFS:  从一个分支遍历到结束  沿一条分支一直搜索
实现方式:递归
基本框架:
DFS(int x, int y, int z)
{
for(遍历分支)
dfs(a,b,c)
}

*vector 链式存储   可迅速插入删除


example:

一.变形课

呃......变形课上Harry碰到了一点小麻烦,因为他并不像Hermione那样能够记住所有的咒语而随意的将一个棒球变成刺猬什么的,但是他发现了变形咒语的一个统一规律:如果咒语是以a开头b结尾的一个单词,那么它的作用就恰好是使A物体变成B物体. 
Harry已经将他所会的所有咒语都列成了一个表,他想让你帮忙计算一下他是否能完成老师的作业,将一个B(ball)变成一个M(Mouse),你知道,如果他自己不能完成的话,他就只好向Hermione请教,并且被迫听一大堆好好学习的道理. 
Input
测试数据有多组。每组有多行,每行一个单词,仅包括小写字母,是Harry所会的所有咒语.数字0表示一组输入结束. 
Output
如果Harry可以完成他的作业,就输出"Yes.",否则就输出"No."(不要忽略了句号) 
Sample Input
so
soon
river
goes
them
got
moon
begin
big
0
Sample Output
Yes.


        
  
Harry 可以念这个咒语:"big-got-them".


代码如下

#include <iostream>
#include<cstdio>
#include<vector>
#include<cstring>
using namespace std;
vector<int> e[30];
bool vis[30];
bool flag;
int i;
void dfs(int x)
{
    vis[x] = 1;
    if(x == 12)
    {
        flag = 1;
        return;     //return 可以看作跳出了调用的这个函数,但只是跳出了当前的,要将所有嵌套的都跳出,用exit
    }
        //return true;
    for(auto &v : e[x])
    {
        if(!vis[v])
            dfs(v);
    }
   // return false;
}
int main()
{
    string str;
    while(cin>>str)
    {
        flag = 0;
        memset(vis, 0, sizeof(vis));    //对vis清零  用0替换并返回vis
        for(i = 0; i < 30; i++)     //26个字母
            e[i].clear();       //对容器清零了
        while(str[0] != '0')
        {
            int len = str.length();
            int be = (int)(str[0] - 'a');
            int en = (int)(str[len - 1] - 'a');
            e[be].push_back(en);    //建立对应的关系,一个存一个
            cin>>str;
        }
        dfs(1);
        if(flag)
            printf("Yes.\n");
        else
            printf("No.\n");
    }
    return 0;
}



1.对于这类题,首先要做的事是建图:将题目转化成树杈形状的图,分支一一明确
这道题中,每个单词的首字母和尾字母就是要找的分叉点

最上层的节点为b

第二层的节点是以b为首字母的单词的尾字母

第三层是以上一层尾字母为首字母的单词的尾字母

......

直到找到m为止

2.对于字母,字符这类相对来说难以进行运算的数据类型,将它们转化为整型的数字,来比较某种关系。
我们让a为0, b为1........m为12.........

3.然后就用容器把1中的关系建立起来:e[be].push_back(en);

4.以b为起始点,调用dfs函数

5.dfs函数

   用for(auto &v : e[x])
    {
        if(!vis[v])
            dfs(v);
    }
这种结构遍历e[x]中的元素,此时,x为第一个节点b

    v依次代表了第二层的节点,不断的调用

*其中,为了防止重复调用同一个字母,设置一个判断函数vis

如果x元素进入过dfs函数,就让vis[x] = 1;

只有当vis[x] != 1 的时候才调用。

  直到 x == 12 时,说明已经找到了,停止调用dfs函数,让flag = 1 结束

*这里结束可以直接用return

return 可以看作跳出了调用的这个函数,但只是跳出了当前的,要将所有嵌套的都跳出,用exit

6.还要注意:对于测试多组数据的题目,一定要记得清空数组和容器

清空数组    memset(vis, 0, sizeof(vis));

清空容器    for(i = 0; i < 30; i++)      e[i].clear();     


二.数油田

The GeoSurvComp geologic survey company is responsible for detecting underground oil deposits. GeoSurvComp works with one large rectangular region of land at a time, and creates a grid that divides the land into numerous square plots. It then analyzes each plot separately, using sensing equipment to determine whether or not the plot contains oil. A plot containing oil is called a pocket. If two pockets are adjacent, then they are part of the same oil deposit. Oil deposits can be quite large and may contain numerous pockets. Your job is to determine how many different oil deposits are contained in a grid. 
Input
The input file contains one or more grids. Each grid begins with a line containing m and n, the number of rows and columns in the grid, separated by a single space. If m = 0 it signals the end of the input; otherwise 1 <= m <= 100 and 1 <= n <= 100. Following this are m lines of n characters each (not counting the end-of-line characters). Each character corresponds to one plot, and is either `*', representing the absence of oil, or `@', representing an oil pocket. 
Output
For each grid, output the number of distinct oil deposits. Two different pockets are part of the same oil deposit if they are adjacent horizontally, vertically, or diagonally. An oil deposit will not contain more than 100 pockets. 
Sample Input
1 1
*
3 5
*@*@*
**@**
*@*@*
1 8
@@****@*
5 5 
****@
*@@*@
*@**@
@@@*@
@@**@
0 0 
Sample Output
0
1
2
2

代码如下:

#include <iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int d[8][2] = {-1,1, -1,0, -1,-1, 0,1, 0,-1, 1,1, 1,0, 1,-1};
bool vis[105][105];
char a[105][105];
int m, n;
bool check(int x, int y)
{
    if(x >= 0 && y >= 0 && x < m && y < n && a[x][y] == '@' && !vis[x][y])
        return true;
    return false;
}
void dfs(int x, int y)
{
    int x0, y0;
    vis[x][y] = 1;
    for(int h = 0; h < 8; h++)
    {

        x0 = x + d[h][0];
        y0 = y + d[h][1];
        if(check(x0, y0))
        {
            dfs(x0, y0);
        }
    }
}
int main()
{
    int i, j, t;
    while(scanf("%d %d", &m, &n) && m + n)
    {
        t = 0;      //一定要初始化
        memset(vis, 0, sizeof(vis));
        memset(a, 0, sizeof(a));
        for(i = 0; i < m; i++)
    {
        for(j = 0; j < n; j++)
        {
            cin>>a[i][j];
        }
    }
    for(i = 0; i < m; i++)
    {
        for(j = 0; j < n; j++)
            if(a[i][j] == '@' && !vis[i][j])
            {
                dfs(i, j);
                t++;
            }
    }
    printf("%d\n", t);
    }
    return 0;
}


1.输入字符型数组cin>>a[i][j];  用scanf会有点问题

2.这道题的建图:

起始点为第一层

起始点8个方向的是 @ 的点组成第二层

.........

直到找不到新的油田的位置为止

3.用一个数组来遍历方向

4.用一个check函数检查是否越界和重复

5.注意测试多组数据的时候一定要将计数器等常量初始化



BFS:从起始点,探索周围的点,直到结束
实现方式:队列
基本框架:

BFS(int x, inty, int z)


BFS(int x, inty, int z)
{
        queue<type> q;
         while(!q.empty())
           {
                   q.pop();
                  for(遍历四周)
                      if(满足条件)
                               q.push();
             }
}


example:

一. strange lift

There is a strange lift.The lift can stop can at every floor as you want, and there is a number Ki(0 <= Ki <= N) on every floor.The lift have just two buttons: up and down.When you at floor i,if you press the button "UP" , you will go up Ki floor,i.e,you will go to the i+Ki th floor,as the same, if you press the button "DOWN" , you will go down Ki floor,i.e,you will go to the i-Ki th floor. Of course, the lift can't go up high than N,and can't go down lower than 1. For example, there is a buliding with 5 floors, and k1 = 3, k2 = 3,k3 = 1,k4 = 2, k5 = 5.Begining from the 1 st floor,you can press the button "UP", and you'll go up to the 4 th floor,and if you press the button "DOWN", the lift can't do it, because it can't go down to the -2 th floor,as you know ,the -2 th floor isn't exist. 
Here comes the problem: when you are on floor A,and you want to go to floor B,how many times at least he has to press the button "UP" or "DOWN"? 
Input
The input consists of several test cases.,Each test case contains two lines. 
The first line contains three integers N ,A,B( 1 <= N,A,B <= 200) which describe above,The second line consist N integers k1,k2,....kn. 
A single 0 indicate the end of the input.
Output
For each case of the input output a interger, the least times you have to press the button when you on floor A,and you want to go to floor B.If you can't reach floor B,printf "-1".
Sample Input
5 1 5
3 3 1 2 5
0
Sample Output
3



代码如下:

#include <iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
int n, a, b, k[205];
bool vis[205];
struct lift
{
    int f;
    int s;
};

int bfs()
{
    queue<lift> q;
    q.push(lift{a, 0});  //结构体初始化的方式
    int r = -1;
    while(!q.empty())
    {
        lift m = q.front();
        vis[m.f] = 1;
        q.pop();
        if(m.f == b)
        {
            r = m.s;
            break;
        }
        int up = m.f + k[m.f - 1];
        int down = m.f - k[m.f - 1];
        if(up <= n && !vis[up])
            q.push(lift{up, m.s + 1});  //都是在这个m结构体下+1;
        if(down >= 1 && !vis[down])
            q.push(lift{down, m.s + 1});

    }

    while(!q.empty()) q.pop();  //清空队列
    return r;
}
int main()
{
    int i;
    while(scanf("%d", &n) && n != 0)
    {
        memset(vis, 0, sizeof(vis));
        scanf("%d %d", &a, &b);
        for(i  = 0; i < n; i++)
            scanf("%d", &k[i]);
        printf("%d\n", bfs());
    }
    return 0;
}

1.结构体的使用:

因为要记录下走的步数,所以不能单纯的整型,而是要使用结构体

结构体初始化的方式     q.push(lift{a(第一个量), 0(第二个量)});  

2.bfs函数

bfs函数主要就是队列,先让第一层进入队列,然后操作到第二层,再让所以第二层入队列

不断访问队列中的首元素,直到找到符合条件的元素。

3.清空队列 while(!q.empty()) q.pop();  


二.pet

One day, Lin Ji wake up in the morning and found that his pethamster escaped. He searched in the room but didn’t find the hamster. He tried to use some cheese to trap the hamster. He put the cheese trap in his room and waited for three days. Nothing but cockroaches was caught. He got the map of the school and foundthat there is no cyclic path and every location in the school can be reached from his room. The trap’s manual mention that the pet will always come back if it still in somewhere nearer than distance D. Your task is to help Lin Ji to find out how many possible locations the hamster may found given the map of the school. Assume that the hamster is still hiding in somewhere in the school and distance between each adjacent locations is always one distance unit.
Input
The input contains multiple test cases. Thefirst line is a positive integer T (0<T<=10), the number of test cases. For each test cases, the first line has two positive integer N (0<N<=100000) and D(0<D<N), separated by a single space. N is the number of locations in the school and D is the affective distance of the trap. The following N-1lines descripts the map, each has two integer x and y(0<=x,y<N), separated by a single space, meaning that x and y is adjacent in the map. Lin Ji’s room is always at location 0. 
Output
For each test case, outputin a single line the number of possible locations in the school the hamster may be found.
Sample Input
1
10 2
0 1
0 2
0 3
1 4
1 5
2 6
3 7
4 8
6 9
Sample Output
2


代码如下:

#include <iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
vector<int>e[100005];
int d;
struct pet
{
    int loc;
    int s;
};

int bfs()
{
    int t = 0;
    queue<pet>q;
    for(auto &v : e[0])	//现让起始位置的进队列
    {
        q.push({v, 0});
    }
    while(!q.empty())
    {
        pet m = q.front();
        q.pop();
        if(m.s >= d)    t++;
        for(auto &w : e[m.loc])
        {
            q.push({w, m.s + 1});
        }
    }
    return t;
}
int main()
{
    int i, n, N, a, b, j;
    scanf("%d", &N);
    for(i = 0; i < N; i ++)
    {
        for(j = 0; j < 100005; j++)
            e[j].clear();
        scanf("%d %d", &n, &d);
        for(j = 0; j < n - 1; j++)
        {
            scanf("%d %d", &a, &b);
            //if(a != 0) h = j;
            e[a].push_back(b);
        }
        printf("%d\n", bfs());
    }
    return 0;
}









  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值