最短Hamilton路径与旅行商问题联系与解决
最短Hamilton路徑與旅行商問題
- 前言
- 最短Hamilton路徑
- 旅行商問題
前言
發(fā)現(xiàn)很多篇博客都是要么直接貼代碼,要么就對dp式子進(jìn)行解釋,沒有說為什么得到這個(gè)式子就很讓人感到無語,這可能就是為什么c站
最短Hamilton路徑
題目轉(zhuǎn)送門
題目意思是從0號(hào)點(diǎn)出發(fā)到n-1點(diǎn)的最短Hamilton路徑 ,我們利用集合的角度來對其進(jìn)行分析
那么這個(gè)轉(zhuǎn)態(tài)的轉(zhuǎn)移需要滿足哪些條件呢
上面條件都滿足的話就可以有轉(zhuǎn)移式子:
dp[i][j]=min(dp[i][j],dp[i?(1<<j)][k]+w[k][j]dp[i][j] = min(dp[i][j],dp[i-(1<<j)][k] + w[k][j]dp[i][j]=min(dp[i][j],dp[i?(1<<j)][k]+w[k][j]
我們就以當(dāng)外層循環(huán)都最后,也就是state轉(zhuǎn)態(tài)表示所以的點(diǎn)都經(jīng)過一次后,第二層循環(huán)為n-1也就是題目所問的終點(diǎn)的時(shí)候,我們在枚舉k的時(shí)候也就是我們在考慮從哪一個(gè)點(diǎn)到終點(diǎn)比較好,如果我們選了一個(gè)點(diǎn),那么這個(gè)點(diǎn)又會(huì)有同樣的子問題。
代碼:
#include<iostream> #include<stdio.h> #include<cstring> using namespace std;const int N = 20 ,M = 1<<20; int f[M][N] ,weight[N][N]; int n;int main(){scanf("%d",&n);for(int i=0;i<n;++i)for(int j = 0;j<n;++j)scanf("%d",&weight[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) // 集合中有jfor(int k = 0;k<n;++k)if(i-(1<<j)>>k & 1 ) //集合中有k,但沒有jf[i][j] = min(f[i][j],f[i-(1<<j)][k] + weight[k][j]);//i-(1<<j) 已經(jīng)在if證明該位置存在了printf("%d\n",f[(1<<n)-1][n-1]);return 0; }旅行商問題
為甚么我要將旅行商問題與Hamilton路徑寫在一起呢,旅行商問題抽象來就是一個(gè)起點(diǎn)任意而終點(diǎn)是自己的Hamilton路徑。
我們回想一下Hamilton路徑中,dp[i][j]dp[i][j]dp[i][j]數(shù)組的含義是:從0出現(xiàn)到終點(diǎn)j,且每一個(gè)點(diǎn)只走一次的集合i的最短路徑,那么我們在計(jì)算完Hamilton路徑后,我們只需要在原來的基礎(chǔ)上加上一條從終點(diǎn)到0的路徑,那么我們就可以構(gòu)成了這個(gè)起點(diǎn)任意的旅行商問題了。
那么問題來了,可能有人會(huì)問為什么是連到0呢不可以是別的點(diǎn)嘛,
首先我們知道如果我們在起點(diǎn)任意選擇的話那么因?yàn)槊疵恳粋€(gè)點(diǎn)最能走一次,那么終點(diǎn)肯定不是這個(gè)點(diǎn),那么我們就可以指定最后的點(diǎn)是0(最后加上0到出發(fā)點(diǎn)的距離)因?yàn)槠瘘c(diǎn)的第一個(gè)點(diǎn)是任意的,最終我們得到的還是在任意可能中的一個(gè)最小值。
那么我們對于這個(gè)思路翻過來想,我們可以讓指向出發(fā)點(diǎn)的點(diǎn)任意,那么出發(fā)點(diǎn)指向的第一個(gè)點(diǎn)就不會(huì)是任意的(可以回想一下概率論中學(xué)到的),因此我們即可以將出發(fā)點(diǎn)的第一個(gè)點(diǎn)定會(huì)0,我們那么這一部分我們就可以轉(zhuǎn)化為Hamilton路徑了。以下是代碼
代碼:
#include <iostream> #include <algorithm> #include <cstring> using namespace std; const int N = 16, M = 1 << N, INF = 0x3f3f3f3f; int n, m, g[N][N]; int f[M][N] ;int main() {cin >> n >> m;memset(g, 0x3f, sizeof g );memset(f, 0x3f, sizeof f);while (m--) {int a, b, c;cin >> a >> b >> c;g[a][b] = c;}for (int i = 0 ; i < n ; ++i)g[i][i] = 0;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] + g[k][j]);}int res = INF;for (int i = 0 ; i < n ; ++i)res = min(res, f[(1 << n) - 1][i] + g[i][0]);if (res == INF)cout << -1 << endl;elsecout << res << endl;return 0; }總結(jié)
以上是生活随笔為你收集整理的最短Hamilton路径与旅行商问题联系与解决的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 高精度算法(加减乘除取模(均可以处理负数
- 下一篇: 动态规划之数字三角形模型