题目

在一个有向图上,从一点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\n", result);
return 0;
}

hiho_1087_哈密顿环的更多相关文章

  1. NPC

    这里的想说的NPC不是Non-Player-Controled,非玩家控制角色,而是Non-determinisitc Polynomial complete problem,它属于一类很特殊的问题, ...

  2. NOIP算法总结与复习

    NOIP算法总结与复习 (看了看李总的蓝皮书,收获颇多,记下此文,以明志--) (一)数论 1.最大公约数,最小公倍数 2.筛法球素数 3.mod规律公式 4.排列组合数,错排 5.Catalan数 ...

  3. NOIP算法小结(转载)

    (一)数论 1.最大公约数,最小公倍数 2.筛法求素数 3.mod规律公式 4.排列组合数,错排 5.Catalan数 6.康托展开 7.负进制 8.中位数的应用 9.位运算 (二)高精度算法 1.朴 ...

  4. [NOIP2017赛前复习第二期]复赛考试技巧与模版-普及组

    考试技巧 1.拿到考卷首先通看题目,按自己感觉的难度排序(普及一般是1-2-3-4了~还是相信出题人不会坑我们的2333) 2.一般来说,普及组前两道题比较简单(大水题啊233~),但是通常坑很多,例 ...

  5. HDU 3488 Tour (最大权完美匹配)【KM算法】

    <题目链接> 题目大意:给出n个点m条单向边边以及经过每条边的费用,让你求出走过一个哈密顿环(除起点外,每个点只能走一次)的最小费用.题目保证至少存在一个环满足条件. 解题分析: 因为要求 ...

  6. 强化学习论文(Scalable agent alignment via reward modeling: a research direction)

     原文地址: https://arxiv.org/pdf/1811.07871.pdf ======================================================== ...

  7. 条件转化,2-sat BZOJ 1997

    http://www.lydsy.com/JudgeOnline/problem.php?id=1997 1997: [Hnoi2010]Planar Time Limit: 10 Sec  Memo ...

  8. hdoj 3488 Tour 【最小费用最大流】【KM算法】

    Tour Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others) Total Submi ...

  9. HihoCoder1087Hamiltonian Cycle(DP状态压缩)

    时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 Given a directed graph containing n vertice (numbered from 1 ...

随机推荐

  1. gcc/g++动态链接库和静态库的链接顺序

    转自:http://withc8212.blog.163.com/blog/static/11656983820109263562854/ so文件:动态库a文件: 静态库exe文件:可执行程序(li ...

  2. Android ActivityThread(主线程或UI线程)简介

    1. ActivityThread功能 它管理应用进程的主线程的执行(相当于普通Java程序的main入口函数),并根据AMS的要求(通过IApplicationThread接口,AMS为Client ...

  3. Thread的六种状态

    线程共有6种状态:在某一时刻只能是这6种状态之一.这些状态由Thread.State这个枚举类型表示,并且可以通过getState()方法获得当前具体的状态类型. 包括(new,runnable,bl ...

  4. MyBatis的返回参数类型和查询结果遍历

    MyBatis的返回参数类型分两种 1. 对应的分类为: 1.1.resultMap: 1.2.resultType: 2 .对应返回值类型: 2.1.resultMap:结果集 2.2.result ...

  5. 第六课 SQLite

    总结:SQLite 1.SQLite的数据类型: NULL(空值).INTEGER(整型值).READL(浮点值).TEXT(字符串值).BLOB(二进制对象); 2.SQLite的应用 2.1 SQ ...

  6. .Net操作注册表--un

    C#操作注册表 导入命名空间 Using MicroSoft.Win32;//64位系统装的64位版本

  7. Know How To Use Check Box Mapping Of Other Values Property In Oracle Forms

    Check Box Mapping of Other Values specifies how any fetched or assigned value that is not one of the ...

  8. CVE-2015-1328(本地提权漏洞)

    /* # Exploit Title: ofs.c - overlayfs local root in ubuntu # Date: 2015-06-15 # Exploit Author: rebe ...

  9. CUBRID学习笔记 31 通过select创建表

    语法 CREATE {TABLE | CLASS} <table_name> [( <column_definition> [,<table_constraint> ...

  10. Struts BaseAction工具类,封装Session,Request,Application,ModelDriven

    package com.ssh.shop.action; import java.io.InputStream; import java.lang.reflect.ParameterizedType; ...