算法具体原理就不讲了,无非是当要返回到前一个结点时将该结点重新设置为未访问。
void DFS(int start, int end)
{
if (start == end) {//找到终点
path.push_back(start);//将终点加入path
for (int i = 0; i < path.size(); i++) //输出路径
{
if (i != path.size() - 1)
cout << inverse_maping[path[i]] << "->";
else
cout << inverse_maping[path[i]] << "\n";
}
path.pop_back();//删除最后一个节点
vis[start] = false;//终点重新设置为未访问
return;
}
vis[start] =true; //将当前结点设置为已访问
path.push_back(start);//加入路径
for (int j =0; j < Adj[start].size(); j++) {//遍历所有子结点
int v = Adj[start][j];//在邻接表中查找子结点v的结点号
if (!vis[v] && path.size()<4) {//检查该节点是否被访问,
//path.size()<4可以限制输出的最大的路径长度
DFS(v, end); //当前是仅输出起点到终点间的结点数目<=2的路径
}
if (j == Adj[start].size() - 1 ) {//子结点全部遍历完成
path.pop_back();//删除路径中最后一个节点
vis[start] = false;//设置为未访问
return;
}
}
}
这里给出一个之前实习的问题:
这次疫情湖北受灾严重,那么为什么湖北这么重要,试证明湖北到全国其他省(不包括两个宝岛)中间都不超过2个省。给定图邻接关系city
用DFS求解湖北到其他所有省份的中间不超过2个省的路径并全部输出(例如:湖北-江西-浙江;湖北-陕西-内蒙古-黑龙江)
#include <string>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<map>
using namespace std;
const int MAXV = 34;//最大结点数
int n;//结点数
bool vis[MAXV] = { false }; //DFS中判断结点是否被访问
vector<int> Adj[MAXV]; //DFS的邻接表
vector<int> path;//DFS的路径
map<string,int>mapping; //完成城市名与结点编号的映射
map<int, string>inverse_maping;//完成结点编号与城市名的映射
string city[MAXV][10] = { //城市间的邻接关系
{ "内蒙古", "黑龙江", "吉林", "辽宁", "河北", "山西", "陕西", "宁夏", "甘肃" },
{ "黑龙江", "内蒙古", "吉林" },
{"吉林", "黑龙江", "内蒙古", "辽宁" },
{"辽宁", "吉林", "内蒙古", "河北"},
{"河北", "辽宁", "内蒙古", "山西", "北京", "天津", "山东", "河南"},
{"河南", "河北", "湖北", "陕西", "山西", "安徽", "山东"},
{"山东", "河北", "河南", "安徽", "江苏"},
{"北京", "河北", "天津"},
{"天津", "河北", "北京"},
{"山西", "河北", "内蒙古", "陕西", "河南"},
{"陕西", "宁夏", "内蒙古", "甘肃", "河南", "山西", "四川", "重庆", "湖北"},
{"宁夏", "陕西", "内蒙古", "甘肃"},
{"甘肃", "宁夏", "内蒙古", "陕西", "青海", "新疆", "四川"},
{"青海", "甘肃", "西藏", "新疆", "四川"},
{"新疆", "西藏", "甘肃", "青海"},
{"西藏", "新疆", "青海", "四川", "云南"},
{"四川", "青海", "西藏", "甘肃", "陕西", "云南", "贵州", "重庆"},
{"云南", "西藏", "四川", "贵州", "广西"},
{"重庆", "陕西", "四川", "贵州", "湖南", "湖北"},
{"贵州", "重庆", "四川", "云南", "广西", "湖南"},
{"广西", "云南", "贵州", "湖南", "广东"},
{"广东", "福建", "江西", "湖南", "广西", "香港", "澳门"},
{"湖南", "湖北", "重庆", "贵州", "广西", "广东", "江西"},
{"江西", "安徽", "湖北", "湖南", "广东", "福建", "浙江"},
{"福建", "浙江", "江西", "广东"},
{"湖北", "河南", "陕西", "重庆", "湖南", "江西", "安徽"},
{"河南", "河北", "山西", "陕西", "湖北", "安徽", "江苏", "山东"},
{"安徽", "河南", "湖北", "江西", "浙江", "江苏", "山东"},
{"浙江", "上海", "江苏", "安徽", "江西", "福建"},
{"上海", "江苏", "浙江"},
{"江苏", "山东", "安徽", "浙江", "上海"},
{"山东", "河北", "河南", "江苏"},
{"香港", "广东"},
{"澳门", "广东"}};
void creat_graph()//将中文关系转换为整型邻接表,并完成城市名与结点编号的映射;
{
for (int i = 0; i < MAXV; i++)//开始映射
{
mapping[city[i][0]] = i;
inverse_maping[i] =city[i][0];
}
//for (map<string, int>::iterator it = mapping.begin(); it != mapping.end(); it++)
//printf("%s %d\n", it->first.c_str(), it->second);
for (int i = 0; i < 34; i++)
for (int j = 1; j < sizeof(city[i]); j++)
{
if (city[i][j] == "")
break;
Adj[i].push_back(mapping[city[i][j]]);//建立int型邻接表
}
}
void DFS(int start, int end)
{
if (start == end) {//找到终点
path.push_back(start);
for (int i = 0; i < path.size(); i++)
{
if (i != path.size() - 1)
cout << inverse_maping[path[i]] << "->";//输出从栈底到栈顶的元素,即为一条路径
else
cout << inverse_maping[path[i]] << "\n";
}
path.pop_back();
vis[start] = false;
return;
}
vis[start] =true;
path.push_back(start);
for (int j =0; j < Adj[start].size(); j++) {
int v = Adj[start][j];
if (!vis[v] && path.size()<4) {
DFS(v, end);
}
if (j == Adj[start].size() - 1 ) {
path.pop_back();
vis[start] = false;
return;
}
}
}
int main()
{
creat_graph();
for (map<string, int>::iterator it = mapping.begin(); it != mapping.end();it++)
if (it->first!="湖北")
DFS(mapping["湖北"],mapping[it->first]);//查找湖北到其它所有城市路径总长度不
//超过4的路径
return 0;
}
部分结果:
湖北->河南->安徽
湖北->河南->江苏->安徽
湖北->陕西->河南->安徽
湖北->湖南->江西->安徽
…
…
…
湖北->湖南->贵州->重庆
湖北->江西->湖南->重庆