最短Hamilton路徑(狀態壓縮DP)
阿新 • • 發佈:2020-07-31
分析:
首先我們要思考如果讓這個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點的權值
那麼這個位運算有什麼用處呢,第一點它是在判斷第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; }