目录
1.题目
来自离散数学的一道作业题,本文将解第(3)问
2.前置知识: 多叉树的遍历
和这道题L56.【LeetCode题解】 电话号码的字母组合非常像,强烈建议各位读者去看看 ;-)
3.代码
算法分析
对a~e进行有序排列组合,根据排列组合公式,显然一共种情况,枚举方法:使用多叉树
如果a是回路的起点,那么有以下多叉树图:
可以发现:
1.递归层数为5
2.回路的节点只有首和尾是重复的,其余节点不能重复,要想在递归过程避开重复节点,需要记忆化处理,即使用一个set存储路径上遍历过的节点,这里和电话号码的字母组合那题不一样
3.将找出的所有回路存储到multimap <int, string> mp中,因为回路长度相同的结果有多个,例如:
a->b->c->d->e->a和a->c->d->b->e->a长度都是20
4.两节点之间的长度使用二维数组存储
5.人工手动一一列举太麻烦,直接DFS遍历多叉树所有情况即可
#include <iostream>
#include <string>
#include <set>
#include <map>
using namespace std;
void dfs(char node, size_t len, size_t arr[123][123], size_t level, string path, set<char>& status, size_t& num, multimap <int, string>& mp)
{
if (level == 5)
{
path += path[0];
len += arr[path[path.size() - 2]][path[0]];
cout << path << ":" << len << endl;
mp.insert(pair<size_t, string>(len, path));
num++;
return;
}
for (char i = 'a'; i <= 'e'; i++)
{
if (status.count(i) == 0)
{
path += i;
status.insert(i);
dfs(i, len + arr[node][i], arr, level + 1, path, status, num, mp);
status.erase(i);//回归后必须删除后才能正确参与下次递归!
path.pop_back();//同时删除路径上的节点
}
}
return;
}
int main()
{
//存储长度信息
static size_t arr['z' + 1]['z' + 1];
arr['a']['b'] = 5;
arr['a']['c'] = 4;
arr['a']['d'] = 5;
arr['a']['e'] = 8;
arr['b']['a'] = 5;
arr['b']['c'] = 2;
arr['b']['d'] = 2;
arr['b']['e'] = 3;
arr['c']['a'] = 4;
arr['c']['b'] = 2;
arr['c']['d'] = 3;
arr['c']['e'] = 5;
arr['d']['a'] = 5;
arr['d']['b'] = 2;
arr['d']['c'] = 3;
arr['d']['e'] = 2;
arr['e']['a'] = 8;
arr['e']['b'] = 3;
arr['e']['c'] = 5;
arr['e']['d'] = 2;
//递归枚举所有情况
size_t num = 0;
multimap <int, string> mp;
cout << "所有的哈密尔顿回路:" << endl;
for (char c = 'a'; c <= 'e'; c++)
{
string path;
set<char> status;
status.insert(c);
path += c;
dfs(c, 0, arr, 1, path, status, num, mp);
}
cout << "无向完全图的所有哈密尔顿回路一共" << num << "种可能";
size_t min_len = (*mp.begin()).first;
cout << "其中路径的最短长度为" << min_len << ",有以下几种方案:" << endl;
for (auto i = mp.begin(); i != mp.end(); i++)
if (i->first == min_len)
cout << i->second << endl;
else
break;
}
3.运行结果
所有的哈密尔顿回路:
最短路径的方案: