日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

最短Hamilton路径与旅行商问题联系与解决

發(fā)布時(shí)間:2025/3/19 编程问答 13 豆豆
生活随笔 收集整理的這篇文章主要介紹了 最短Hamilton路径与旅行商问题联系与解决 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

最短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)移需要滿足哪些條件呢

  • 在當(dāng)前的路徑的狀態(tài)中,i對應(yīng)的位置需要為1,也就是當(dāng)起的終點(diǎn)需要出現(xiàn)在路徑上。
  • 對于中間節(jié)點(diǎn)k而言,由每一個(gè)點(diǎn)只能出現(xiàn)一次,因此我們?nèi)サ鬷之后對應(yīng)的路徑的集合需要有節(jié)點(diǎn)k。
  • 上面條件都滿足的話就可以有轉(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)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。