zoukankan      html  css  js  c++  java
  • 最短Hamilton路径(状态压缩DP)

     分析:

         首先我们要思考如果让这个NP完全题目复杂度降低,那么可以优先考虑到使用位运算,状态压缩等解决思路。

        然后接着思考,我们可以发现,我们所需要的不是整个方案,而只是方案最优解,所以我们只需要记录当前这个方案的最优解即可,那么我们考虑的状态,不久只有,在当前方案i中,目前抵达的点是j。
        现在既然装填已经确定好了当前点j,那么这个j点是由哪一个状态移动而来的呢?我们可以选择k,也就是说我们的状态转移方程可以为
          f[i][j]=min(f[i][j],f[i^(1<<j)][k]+w[k][j]

        以上转移方程,w数组为权值 ,也就是w[k][j]是k点到j点的权值
        i^(1<<j)的意思是,i 异或 1右移j位,具体来说就是i这个方案集合 xor 10……0,(其中1的位置在第j位)。
        那么这个位运算有什么用处呢,第一点它是在判断第j位的情况,第二点位运算处理速度很快。

    import java.util.*;
    class Main {
        
        public static void main(String[] args) {
            
            Scanner sc = new Scanner(System.in);
            int n = sc.nextInt();
            int[][] w = new int[n][n];
            for(int i = 0; i < n; i++) {
                for(int j = 0; j < n; j++) {
                    w[i][j] = sc.nextInt();
                }
            }
            int[][] f = new int[1<<n][n];
            for(int[] d : f) Arrays.fill(d,Integer.MAX_VALUE / 2);
            f[1][0] = 0;
            for(int i = 0; i < 1 << n; i++) {
                for(int j = 0; j < n; j++) {
                    if(((i >> j) & 1) != 0) {
                        for(int k = 0; k < n; k++) {
                            if((((i - (1 << j)) >> k) & 1) != 0) {
                                f[i][j] = Math.min(f[i][j],f[i-(1<<j)][k] + w[k][j]);
                            }
                        }
                    }
                }
            }
            System.out.print(f[(1<<n)-1][n-1]);
        }
    }
    #include <iostream>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    const int N = 20, M = 1 << N;
    
    int n;
    int f[M][N];
    int w[N][N];
    
    
    int main() {
        cin >> n;
        for(int i = 0; i < n; i++) {
            for(int j = 0; j < n; j++) {
                cin >> w[i][j];
            }
        }
        memset(f,0x3f,sizeof f);
        f[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) {
                            f[i][j] = min(f[i][j],f[i-(1 << j)][k] + w[k][j]);
                        }
                    }
                }
            }
        }
        cout << f[(1 << n) - 1][n-1];
        return 0;
    }
  • 相关阅读:
    linux命令大全
    linux几个常用命令
    linux基础入门命令自我总结——乱
    linux标准目录的结构——各个目录都是干啥的
    python基础知识9——模块2——常见内置模块
    python基础知识8——模块1——自定义模块和第三方开源模块
    手写数据结构-链表
    手写数据结构-基于动态数组的循环队列
    手写数据结构-基于动态数组的队列
    手写数据结构-基于动态数组的栈
  • 原文地址:https://www.cnblogs.com/yonezu/p/13409436.html
Copyright © 2011-2022 走看看