dp tsp問題 海賊王之偉大航路

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;
    }



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章