hiho_1087_哈密顿环
题目
在一个有向图上,从一点A出发,经过所有除A的顶点一次且仅经过一次,最后到达起始点A,所形成的路径为哈密顿环。两个哈密顿环不同,当且仅当路径上的任意一个顶点P的下一个顶点不同。
给出一个顶点数目为 <= 12, 边的数目 <= 200(有可能有重边)的有向图的所有可能的哈密顿环的总数。
分析
哈密顿环经过所有的顶点,因此可以从任何一个顶点出发(在程序中就选择起始点为节点0);如果两个顶点之间有重边,那么这些重边对于哈密顿环是等价的,因此在构建图的时候,要去重边。
使用深度优先搜索可以求出所有哈密顿环的总数,但是估算一个复杂度: 假设每个顶点都连接其他10个顶点,那么深度优先搜索复杂度约 10^10,不能接受。因此可以考虑使用记忆化搜索结合状态压缩:
1、状态用两个维度表示:(1)经过路径(从某个点开始到达节点0)上所覆盖的点;(2)经过的路径的起始点。
2、最多一共12个点,可以用一个整数的低12个比特表示经过的路径中这12个点是否被经过。因此使用 dp[status_to_visit][node] 表示从节点node开始,经过的节点的位图为 status_to_visit ,最终到达节点0所有不同的路径的总数。
利用记忆化深度优先搜索,求出最终的结果.
明确状态很重要,计算清楚边界状态很重要!
明确状态很重要,计算清楚边界状态很重要!
明确状态很重要,计算清楚边界状态很重要!
实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | #include<iostream> #include<stdio.h> #include<algorithm> #include<unordered_map> #include<list> #include<string> #include<string.h> #include<set> using namespace std; int dp[8200][13]; //dp[status][node] 表示从node出发,最终到达点0,遍历的点的状态形成 status 时可以走的路径数目 bool connected[13][13]; struct Edge{ int to; int next; }; Edge gEdges[220]; int gEdgeIndex; int gHead[13]; bool gVisited[13]; void InsertEdge( int u, int v){ if (connected[u][v]) //如果两个节点A和B之间有多条边直接从A连接到B,则只记录一次 return ; connected[u][v] = true ; int e = gEdgeIndex++; gEdges[e].to = v; gEdges[e].next = gHead[u]; gHead[u] = e; } void Init(){ gEdgeIndex = 0; memset(gEdges, -1, sizeof (gEdges)); memset(gHead, -1, sizeof (gHead)); memset(dp, -1, sizeof (dp)); memset(connected, false , sizeof (connected)); memset(gVisited, false , sizeof (gVisited)); } //用记忆化搜索实现 动态规划 //从node开始,经过的各个节点的位图为 status_to_visit,status_to_visit 中的各个节点经过 //且只经过一次,最终到达节点0. 所有可能的路径总数 int Dfs( int status_to_visit, int node){ if (dp[status_to_visit][node] != -1) return dp[status_to_visit][node]; //当前节点之前被访问过一次 if ((status_to_visit & (1 << node)) == 0) return dp[status_to_visit][node] = 0; int result = 0; for ( int e = gHead[node]; e != -1; e = gEdges[e].next){ int v = gEdges[e].to; int new_status = status_to_visit & (~(1 << node)); result += Dfs(new_status, v); } return dp[status_to_visit][node] = result; } int main(){ int n, m, u, v; Init(); scanf( "%d %d" , &n, &m); for ( int i = 0; i < m; i++){ scanf( "%d %d" , &u, &v); InsertEdge(u - 1, v - 1); } //初始状态,从0节点开始,最终到达节点0. status_to_visit = 0 是应为要从0开始到达0, //在开始的时候,位图为 111111,递归到下一层时为 111110.到最后再到达0时候的status_to_visit 为 000000 dp[0][0] = 1; int result = Dfs((1 << n) - 1, 0); printf( "%d\n" , result); return 0; } |
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步