TSP問題是一個np問題 但是我們可以通過僞多項式算法來實現 就是用狀態壓縮dp
dp[i][j]:i是目前已經走過的城市的狀態 j是在此狀態下最後一個到達的城市 dp[i][j]表示到此時的最小用時 如果狀態轉移不合法 設置爲
-1 那怎麼來遞推呢 我們想一想 如果一個i要從 00000000001(二進制表示) 走過來 那麼所走的狀態一定都是小於i的 比如
i=000000101 要從 000000001 或者 0000000100走過來一樣 所以i從小到大就可以了!
狀態轉移方程dp[i][j]=min(dp[i][j],dp[state][k]+mat[k][j]) 其中state 和k是枚舉合法的 。
7:海賊王之偉大航路
- 總時間限制:
- 1000ms
- 內存限制:
- 65536kB
- 描述
-
“我是要成爲海賊王的男人!”,路飛一邊喊着這樣的口號,一邊和他的夥伴們一起踏上了偉大航路的艱險歷程。
路飛他們偉大航路行程的起點是羅格鎮,終點是拉夫德魯(那裏藏匿着“唯一的大祕寶”——ONE PIECE)。而航程中間,則是各式各樣的島嶼。
因爲偉大航路上的氣候十分異常,所以來往任意兩個島嶼之間的時間差別很大,從A島到B島可能需要1天,而從B島到A島則可能需要1年。當然,任意兩個島之間的航行時間雖然差別很大,但都是已知的。
現在假設路飛一行從羅格鎮(起點)出發,遍歷偉大航路中間所有的島嶼(但是已經經過的島嶼不能再次經過),最後到達拉夫德魯(終點)。假設他們在島上不作任何的停留,請問,他們最少需要花費多少時間才能到達終點?
- 輸入
- 輸入數據包含多行。
第一行包含一個整數N(2 < N ≤ 16),代表偉大航路上一共有N個島嶼(包含起點的羅格鎮和終點的拉夫德魯)。其中,起點的編號爲1,終點的編號爲N。
之後的N行每一行包含N個整數,其中,第i(1 ≤ i ≤ N)行的第j(1 ≤ j ≤ N)個整數代表從第i個島嶼出發到第j個島嶼需要的時間t(0 < t < 10000)。第i行第i個整數爲0。 - 輸出
- 輸出爲一個整數,代表路飛一行從起點遍歷所有中間島嶼(不重複)之後到達終點所需要的最少的時間。
- 樣例輸入
-
樣例輸入1: 4 0 10 20 999 5 0 90 30 99 50 0 10 999 1 2 0 樣例輸入2: 5 0 18 13 98 8 89 0 45 78 43 22 38 0 96 12 68 19 29 0 52 95 83 21 24 0
- 樣例輸出
-
樣例輸出1: 100 樣例輸出2: 137
- 提示
- 提示:
對於樣例輸入1:路飛選擇從起點島嶼1出發,依次經過島嶼3,島嶼2,最後到達終點島嶼4。花費時間爲20+50+30=100。
對於樣例輸入2:可能的路徑及總時間爲:
1,2,3,4,5: 18+45+96+52=211
1,2,4,3,5: 18+78+29+12=137
1,3,2,4,5: 13+38+78+52=181
1,3,4,2,5: 13+96+19+43=171
1,4,2,3,5: 98+19+45+12=174
1,4,3,2,5: 98+29+38+43=208
所以最短的時間花費爲137
單純的枚舉在N=16時需要14!次運算,一定會超時。 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <string> #include <iostream> #include <sstream> #include <ostream> #include <algorithm> #include <ctype.h> #include <cmath> #include <queue> #include <set> #include <map> #include <vector> #define inf 1e9+7 #define pi acos(-1) #define natrule exp(1) using namespace std; #pragma comment(linker, "/STACK:1024000000,1024000000") int mat[50][50]; int dp[500000][20]; int main(){ int n; while(cin>>n){ for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ cin>>mat[i][j]; } } memset(dp,-1,sizeof(dp)); int all=(1<<n)-1; dp[1][1]=0; for(int i=2;i<=all;i++) { for(int k=1;k<=n;k++) { int c=1<<(k-1); if((c&i)==0) continue; int state=i-c; for(int j=1;j<=n;j++){ if(dp[state][j]==-1) continue; else { if(dp[i][k]==-1) dp[i][k]=dp[state][j]+mat[j][k]; else dp[i][k]=min(dp[i][k],dp[state][j]+mat[j][k]); } } } } /* for(int i=1;i<=((1<<n)-1);i++){ for(int j=1;j<=n;j++){ cout<<dp[i][j]<<' '; } } cout<<endl;*/ cout<<dp[(1<<n)-1][n]; } return 0; }