zoukankan      html  css  js  c++  java
  • 91. 最短Hamilton路径【状压DP】

    描述

    给定一张 nn 个点的带权无向图,点从 0~n-1 标号,求起点 0 到终点 n-1 的最短Hamilton路径。 Hamilton路径的定义是从 0 到 n-1 不重不漏地经过每个点恰好一次。

    输入格式

    第一行输入整数nn。

    接下来nn行每行nn个整数,其中第ii行第jj个整数表示点ii到jj的距离(记为a[i,j])。

    对于任意的x,y,zx,y,z,数据保证 a[x,x]=0,a[x,y]=a[y,x] 并且 a[x,y]+a[y,z]>=a[x,z]。

    输出格式

    输出一个整数,表示最短Hamilton路径的长度。

    数据范围

    1≤n≤201≤n≤20
    0≤a[i,j]≤1070≤a[i,j]≤107

    输入样例:

    5
    0 2 4 5 1
    2 0 6 5 3
    4 6 0 8 3
    5 5 8 0 5
    1 3 3 5 0
    

    输出样例:

    18

     题解

    本题如果用朴素算法枚举每一种路径,找最小值时间复杂度为Oleft ( n * n! 
ight ) 

    用状态压缩DP复杂度为Oleft ( 20*2^{20} 
ight )

    状态转移方程 dp[i][j] = min(dp[i][j], dp[ioplus (1 << j)][k] + a[k][j]);

    i 表示 方案集合  j表示枚举的点   k 表示j的上一个点 

    关于位运算  

    ( n >> k ) & 1  表示n在二进制表示下的第k位

    n ^ ( 1 << k ) 表示n 在二进制表示下的第k位取反

    #include <iostream>
    #include <cstdio>       //EOF,NULL
    #include <cstring>      //memset
    #include <cmath>        //ceil,floor,exp,log(e),log10(10),hypot(sqrt(x^2+y^2)),cbrt(sqrt(x^2+y^2+z^2))
    #include <algorithm>    //fill,reverse,next_permutation,__gcd,
    #include <string>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <map>
    using namespace std;
    #define rep(i, a, n)        for (int i = a; i < n; ++i)
    #define sca(x)            scanf("%d", &x)
    #define sca2(x, y)        scanf("%d%d", &x, &y)
    #define sca3(x, y, z)        scanf("%d%d%d", &x, &y, &z)
    #define pri(x)            printf("%d
    ", x)
    #define pb    push_back
    #define mp    make_pair
    typedef pair<int, int>        P;
    typedef long long        ll;
    int dp[1 << 20][20];
    int n;
    int a[20][20];
    int main()
    {
        sca(n);
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < n; j++)
            {
                sca(a[i][j]);
            }
        }
        memset(dp, 0x3f, sizeof dp);
        dp[1][0] = 0;
        for (int i = 0; i < 1 << n; i++)
        {
            for (int j = 0; j < n; j++)
            {
                if (i >> j & 1) {         
                    for (int k = 0; k < n; k++)
                    {
                        if ((i ^  1 << j) >> k & 1) {
                            dp[i][j] = min(dp[i][j], dp[i ^ 1 << j][k] + a[k][j]);
                        }
                    }
                }
            }
        }
        pri(dp[(1<<n)-1][n-1]);
    }
     
  • 相关阅读:
    求公约数和比值
    HTML5 文件上传
    js判断是pc还是移动端
    ssm整合
    如何获取数据表中自增主键的值
    MyBatis全局配置文件标签详解
    MyBatis介绍及使用
    基于Spring MVC的文件上传和下载功能的实现
    Spring IOC容器交给application域对象管理
    SpringMVC的简单介绍及使用
  • 原文地址:https://www.cnblogs.com/llke/p/10780078.html
Copyright © 2011-2022 走看看