参考博客
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等标志数据的初始化工作