回溯法-哈密顿回路

G中经过每个顶点一次且仅一次的回路称作哈密顿回路欧拉回路要求通过每条边一次且仅仅一次,而哈密顿回路图则要求通过每个顶点一次且仅仅一次。哈密顿回路图有一个重要的问题:traveling salesperson problem,TSP,就是所谓的 货郎担 的问题即要求在图中发现经过所有顶点且总路程最短的回路。

求解哈密顿问题代码

#include <iostream>
#include <vector>
using namespace std;

void dfs(int depth, int n, const int a[20][20], vector<vector<int>>& v, vector<int>&path)
//depth为递归层数,n为图节点数,二维数组a[20][20]存放图的邻接矩阵,二维向量v记录哈密顿回路
//一维向量path[i]存放前往的第i个城市(结点)为path[i],path[0]=1(出发点始终为第一个节点)
{
	if (depth == n )//递归出口
	{if(a[(path[depth - 1] - 1)][0] == 1)//能返回出发城市(出发点)才是哈密顿回路
	v.push_back(path); 
	path.resize(n, 1);//清除上一条哈密顿回路痕迹的干扰
	}
	else
	{
		for (int j = 1; j <= n; j++)//枚举下一个结点的各种可能
		{
			path[depth] = j;
			bool flag = true;
			for (int i = 0; i < depth; i++)
if ((a[(path[depth-1]-1)][j - 1] == 0) || (a[(path[depth - 1]-1)][j - 1] == 1 && path[i]== j))
//减枝函数,减去当前不可前往的结点和之前已前往的结点
				{
					flag = false;
						break;
				}
			if (flag) dfs(depth + 1, n, a, v, path);//若满足约束条件和限界函数,递归下一层
		}
	}
}
int main()
{
	int n;
	int a[20][20];
	//测试用例: a[5][5]={{0,1,0,1,0},{1,0,1,0,1},{0,1,0,1,1},{1,0,1,0,1},{0,1,1,1,0}}
	cout << "图的节点个数为:";
	cin >> n;
	cout << "请输入图的邻接矩阵" << endl;//以出发点为第一个节点
	for (int i = 0; i < n; i++)
		for (int j = 0; j < n; j++)
			cin >> a[i][j];
	vector<vector<int>>v;
	vector<int> path;
	path.resize(n, 1);
	dfs(1, n, a, v, path);
	int count = v.size();
	if (count == 0)
		cout << "该图不存在哈密顿回路";
	else {
		cout << "该图存在" << count << "个哈密顿回路," << "分别是:" << endl;
		for (auto it = v.begin(); it != v.end(); it++)
		{
			for (auto z = (*it).begin(); z != (*it).end(); z++)
				cout << *z<<" ";
			cout << endl;
		}
	}
}

测试用例:
测试用例
测试用例输出结果:
测试用例

### 使用回溯法求解哈密顿回路并应用剪枝技术 当采用回溯算法解决哈密顿回路问题时,通过引入有效的剪枝策略可以显著减少不必要的计算路径数量。具体而言,在构建可能的解决方案过程中,每当尝试向当前部分路径添加新节点之前都会执行一系列验证操作来决定是否继续探索该分支。 #### 剪枝条件一:连通性检查 在每次准备加入下一个顶点到现有路径前,先确认此动作不会破坏图的整体连通性质。如果发现即将形成的子图已经无法覆盖剩余未访问过的全部顶点了,则立即终止这条路线的发展[^1]。 #### 剪枝条件二:唯一邻接检验 对于每一个正在考虑连接的新顶点v来说,除了要保证它尚未被遍历过之外,还应确保其至少有一个邻居w满足两个特性——既不是起点也不是终点,并且目前也处于未标记状态。这样的安排有助于提前排除那些注定会失败的情况,从而加快搜索速度。 #### 实现示例代码 下面给出了一段Python实现片段用于展示上述原则的应用: ```python def hamiltonian_cycle(graph, path=None, pos=0): if path is None: path = [] n = len(graph) if not path: for i in range(n): # 尝试从不同起始位置出发 result = hamiltonian_cycle(graph, [i], 1) if result: return result return None elif len(path) == n and graph[path[-1]][path[0]] != float('inf'): return path + [path[0]] else: last_node = path[pos-1] candidates = set(range(len(graph))) - set(path[:pos]) for next_node in sorted(candidates, key=lambda v: sum([graph[v][j]!=float('inf') for j in (set(range(n))-set(path))])): if all((next_node!=start_end or start_end==last_node) for start_end in {path[0], path[-1]}): new_path = list(path)+[next_node] # 进行必要的预判以实施剪枝逻辑 if check_connectivity(new_path, graph) \ and has_unvisited_neighbors(next_node, new_path, graph): found_solution = hamiltonian_cycle(graph, new_path, pos+1) if found_solution: return found_solution return None def check_connectivity(current_path, g): """辅助函数:判断给定的部分路径是否会形成孤立分量""" pass # 需要根据实际情况定义具体的判定方法 def has_unvisited_neighbors(node_index, current_path, adjacency_matrix): """辅助函数:检测指定结点是否存在可选后续结点""" unvisited_nodes = set(range(len(adjacency_matrix))) - set(current_path[:-1]) neighbor_counts = [ int(adjacency_matrix[node_index][other]>0) * int(other in unvisited_nodes) for other in range(len(adjacency_matrix)) ] return any(neighbor_counts) if __name__ == "__main__": sample_graph = [[0, 1, 0, 1], [1, 0, 1, 1], [0, 1, 0, 0], [1, 1, 0, 0]] solution = hamiltonian_cycle(sample_graph) print(solution) ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值