• 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所有不同的路径的总数。 
        利用记忆化深度优先搜索,求出最终的结果. 
        明确状态很重要,计算清楚边界状态很重要! 
        明确状态很重要,计算清楚边界状态很重要! 
        明确状态很重要,计算清楚边界状态很重要!

    实现

    #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
    ", result);
    	return 0;
    }
    
  • 相关阅读:
    2020.06.09 手写数字识别-小数据集
    2020.6.1 深度学习-卷积
    2020.05.22 垃圾邮件分类2
    2020.05.08 分类与监督学习,朴素贝叶斯分类算法
    2020.04.27 主成分分析
    2020.04.27 特征选择
    2020.04.26 逻辑回归实践
    2020.04.24 逻辑归回
    2020.04.21 线性回归算法
    15 手写数字识别-小数据集
  • 原文地址:https://www.cnblogs.com/gtarcoder/p/5558711.html
Copyright © 2020-2023  润新知