最短Hamilton路徑

2022-05-09 16:03:15 字數 1362 閱讀 8651

題目思路怎麼可能時二進位制dp呢?這才第一章啊。

應該吧然後我用了bfs暴力搜尋。

首先,我們發現題目是乙個無向完全圖,雖然我做完還是不知道a[x,y]+a[y,z]>=a[x,z]有什麼用其實這也不重要,我用bfs的管我屁事。好像dp的也無關緊要吧

都是從\(0\)開始那我們就不管了,因為要求每個點都走一遍,所以我們肯定要用某種方式把我們走過的點表示出來,沒錯,就是二進位制,而這裡\(n<=20\),所以二進位制第\(i\)位就代表了這個點有沒有走過,同時也有乙個很重要的資訊還要記錄就是我們當前走到了哪個點,不難想出,利用這兩個資訊就足以用這個路徑進行轉移了,什麼,你說有很多條路徑滿足這個資訊?這就是壓縮資訊的精髓了,把一些類似的路徑取乙個最小值進行轉移,同時不影響答案(插頭dp其實也是類似的思路)。

仔細想想你會發現,滿足同兩個資訊的一些路徑在轉移上都是一樣的,且最後盡可能是走過的邊權和最小的路徑可以轉移成功,所以只要用邊權和最小的路徑代表這些路徑就行了。

然後對於\(f[i][j]\)(\(i\)記錄路徑,\(j\)表示目前到了哪個點)的轉移就是:

\(f[i+(1<<(k-1))][k]=f[i][j]+a[j][k]\)。

然後就可以愉快的bfs啦。

但是bfs比較容易bfs,如果想要降空間的話還是用dp吧,但是時間複雜度是一樣的,只不過dp利用二進位制的乙個性質:走過\(k\)個點的路徑轉移完後,\(k+1\)個點的路徑的\(f\)值就全部出來了,所以只要把含有\(k\)個\(1\)的全部\(f\)轉移完之後去轉移\(k+1\)個\(1\)就行了,當然,dp也可以找這條路徑是由哪些路徑轉移來的進行dp,時間複雜度也是一樣的(如\(f[3][2]\)會主動去找\(f[1][1]\)來更新自己),只不過乙個是更新別人,乙個是找別人更新自己罷了(還有一些更神奇的轉移順序我就不說了)。

#include#include#define  n  22

#define m 1100000

using namespace std;

int n,a[n][n],f[m][n]/*m表示走過的裝填,n表示目前所在的位置*/;

struct qmq

list[16000000];int head,tail;

inline int mymin(int x,int y)

int main()

for(int i=1;i<=n;i++)

list[1].x=1;list[1].y=1;f[1][1]=0;

head=1;tail=1;

while(head<=tail)

}} int ans=f[limit][n];

printf("%d\n",ans);

return 0;

}

最短Hamilton路徑

給定一張 n 個點的帶權無向圖,點從 0 n 1 標號,求起點 0 到終點 n 1 的最短hamilton路徑。hamilton路徑的定義是從 0 到 n 1 不重不漏地經過每個點恰好一次。輸入格式 第一行輸入整數n。接下來 n 行每行n個整數,其中第i行第j個整數表示點i到j的距離 記為a i,j...

最短Hamilton路徑

題目描述 給定一張 n n 20 個點的帶權無向圖,點從 0 n 1 標號,求起點 0 到終點 n 1 的最短hamilton路徑。hamilton路徑的定義是從 0 到 n 1 不重不漏地經過每個點恰好一次。輸入第一行乙個整數n。接下來n行每行n個整數,其中第i行第j個整數表示點i到j的距離 乙個...

最短Hamilton路徑

本題如果使用暴搜的話會超時。因為是無向圖,所以最終我們只關心不重不漏的一條路徑的長度,而不關心內部先走哪個點後走哪個點。所以,我們需要對每個點進行位置標記,當然可以開乙個visited陣列記錄,但為了操作簡便以及空間複雜度,使用二進位制位表示更為簡便。某一位為1表示對應的該點被訪問過。因此乙個二進位...