DFS+BFS-公路搜索【单向公路-OJ1107】

参考博客

http://www.cnblogs.com/xuning/p/3321733.html

https://www.cnblogs.com/whywhy/p/4888632.html

https://blog.csdn.net/qq_34542903/article/details/51084912

题目描述

某个地区有许多城镇,但并不是每个城镇都跟其他城镇有公路连接,且有公路的并不都能双向行驶。现在我们把这些城镇间的公路分布及允许的行驶方向告诉你,你需要编程解决通过公路是否可以从一个城镇到达另一个城镇。(我们规定,城镇自己跟自己可互相到达,即A可到达A).

 

输入要求

第一行只有一个数N,下面将跟着2N行数据. 在前N行数据中,对于每行数据,最开头一个数字number,表明这一行总共有number个数,number的下一个数为i,代表编号为i的那个城镇.这行余下的就是跟i有公路连接的城镇的名单,且只能从城镇i驶向其他城镇。如 4 1 2 3,表明:此行有4个数,跟城镇1有公路连接的城镇是编号为2和3的城镇,且只允许从城镇1驶向城镇2和3,而不能从2到1或3到1。 在后N行数据中,每行由两个数字组成a,b. 对于每个输入的数有如下关系 0 <= input_number <= 1000 .

 

输出要求

对于输入数据中的每个a,b,判断是否可以从城镇a通过公路到达城镇b,如果可以,输出Yes;否则输出No.

 

输入样例

3

4 1 2 3

3 4 5

3 5 8

1 2

1 8

4 8

 

输出样例

Yes

No

Yes

 

思路分析

典型的DFS(深度优先搜索)、BFS(广度优先搜索)问题,涉及有关知识点:队列、图。

 

解决方式

1.DFS

2.BFS

 

涉及相关知识点和链接

图的概念:https://baike.baidu.com/item/图/13018767#viewPageContent

队列的概念:https://baike.baidu.com/item/队列/14580481?fr=aladdin

搜索算法:https://baike.baidu.com/item/搜索算法/2988274?fr=aladdin

C++中队列的使用和实现:http://www.cnblogs.com/xuning/p/3321733.html

DFS与BFS详解(两种搜索的模板写的很好):https://www.cnblogs.com/whywhy/p/4888632.html

 

AC代码

1.DFS

#include<stdio.h>
#include<string.h>
#define MAX 1010
int vis[MAX];//记录走过的城镇,如果为0则表示没走过,为1表示走过,初始为0
int roadmap[MAX][MAX];//用二维数组的形式记录由一个城镇能到达的其他城镇的编号
int len[MAX];//每个城镇能到达其他城镇的数量(用于节省时间)
int flag;//判断是否能到达目的地
int bg,ed;//深搜起始点和终止点。
void DFS(int bg)
{
    int i;
    if(bg==ed)//起始点和终止点相同,可以到达。
    {
        flag = 1;
        return;
    }
    
    for(i = 0; i < len[bg]; i++)
    {
        if(vis[roadmap[bg][i]] == 0)//城镇[bg]到城镇[i]没有走过
        {
            vis[roadmap[bg][i]] = 1;//标记为已经走过
            DFS(roadmap[bg][i]);//继续往下进行深搜
        }
    }

}
int main()
{
    int N,n,num,i,j;
    memset(roadmap,0,sizeof(roadmap));
    scanf("%d",&N);
    for(i = 0; i < N; i++)
        {
            scanf("%d",&n);
            scanf("%d",&num);
            len[num] = n - 2;//除去此列数据数量和起始编号
            for(j = 0; j < n - 2; j++)
            {
                scanf("%d",&roadmap[num][j]);
            }
        }
    for(i = 0; i < N; i++)
    {
        scanf("%d %d",&bg,&ed);
        memset(vis,0,sizeof(vis));//清零标记
        flag = 0;
        DFS(bg);
        if(flag == 1)
            printf("Yes\n");
        else
            printf("No\n");
    }
    return 0;
}

 

2.BFS

#include<stdio.h>
#include<string.h>
#include<queue>
#define MAX 1010
using namespace std;
int vis[MAX];//记录走过的城镇,如果为0则表示没走过,为1表示走过,初始为0
int roadmap[MAX][MAX];//用二维数组的形式记录由一个城镇能到达的其他城镇的编号
int len[MAX];//每个城镇能到达其他城镇的数量(用于节省时间)
int flag;//判断是否能到达目的地
int bg,ed;//广度搜索的起始点和终止点。
queue<int> que;//队列定义
void BFS()
{
    while(!que.empty())//如果队列不为空
    {
        int fir = que.front();//读取队列中的第一个元素fir
        que.pop();//将第一个元素移出队列
        if(fir == ed)
        {
            flag = 1;
            return;
        }
        for(int i = 0; i < len[fir]; i++)
        {
            if(vis[roadmap[fir][i]] == 0)//此点没有被访问过
            {
                vis[roadmap[fir][i]] = 1;//标记此点已经访问
                que.push(roadmap[fir][i]);//将此点推进队列
            }
        }
    }
}
int main()
{
    int N,n,num,i,j;
    memset(roadmap,0,sizeof(roadmap));
    scanf("%d",&N);
    for(i = 0; i < N; i++)
        {
            scanf("%d",&n);
            scanf("%d",&num);
            len[num] = n - 2;//除去此列数据数量和起始编号
            for(j = 0; j < n - 2; j++)
            {
                scanf("%d",&roadmap[num][j]);
            }
        }
    for(i = 0; i < N; i++)
    {
        scanf("%d %d",&bg,&ed);
        flag = 0;//标记清零
        vis[bg] = 1;//起始点标记为已经访问
        que.push(bg);//将起始点推入队列
        BFS();//深搜
        if(flag == 1)
            printf("Yes\n");
        else
            printf("No\n");
    }
    return 0;
}

 

总结及错误分析

BFS与DFS需要的准备工作:

1.用数组形式储存相关图(map[][]) 

2.用一个数组(vis[])记录已经访问过的节点

(3.可用一个额外数组(len[])记录元素个数节省时间)

错误分析:

1.没用VIS[]数组正确记录访问情况,导致超时和结果错误。

2.对于多组数据的VIS[]以及flag等标志数据的初始化工作

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值