題目描述
某鄉有n個村莊(1
201 120),有乙個售貨員,他要到各個村莊去售貨,各村莊之間的路程s(0 < s< 1000 )s(0s( 0< s<10 00)是已知的,且a村到b村與b村到a村的路大多不同。為了提高效率,他從商店出發到每個村莊一次,然後返回商店所在的村,假設商店所在的村莊為1,他不知道選擇什麼樣的路線才能使所走的路程最短。請你幫他選擇一條最短的路。 輸入格式: 村莊數n和各村之間的路程(均是整數)。 輸出格式: 最短的路程。 說明 輸入解釋 3 0 2 1 1 0 2 2 1 0 題目分析 tsp問題,也算是狀壓dp經典吧 我們以一串二進位制數表示村莊的集合(狀態) 1表示該村莊訪問過,0表示沒有dp[ i][j ]dp[i][j] dp[i][ j]表示從起點到第j號點,且到達時狀態恰好為i的最短路 則最後答案就是min (dp[ (1 < −1][ i]+m ap[i ][1] )min(dp[(1<< n) -1][i] + map[i][1]) min(dp [(1< −1][ i]+m ap[i ][1])(2 <=i <=n )(2<=i<=n) (2<=i <=n )其中map陣列是題目給定的各村莊間距離 而求取dp陣列的方法,我們可以借鑑floyd的思想 具體**: (int i= 0;i<=(1 <;++i) for( int j= 1;j<=n; ++j)if( ((1<&i )==0 )for (int k= 1;k<=n; ++k)if( ((1<&i)) dp[i|(1 <][j] =min (dp[i|(1 <][j] ,dp[i] [k]+ rem[k] [j]) ;如何解釋呢 第一層迴圈 i列舉每個狀態 第二層迴圈 j列舉下一步到達的點 if( !( (1 << j-1) & i) ) 這句判斷 j 是否已訪問 1左移j-1位,則此時只有第j位是1 若狀態 i 的第 j 位為1,則&與運算返回1,表示已訪問,否則沒訪問 第三層迴圈列舉中介點k, 其中if語句判斷同上 d p[ i∣(1 < 1)][ j]=m in(d p[i∣ (1 < 1)][ j],d p[i] [k]+ rem[ k][j ]) ;dp[i|(1[i∣( 1< 1)][ j]=m in(d p[i∣ (1< 1)][ j],d p[i] [k]+ rem[ k][j ]);i∣( 1< 1) i|(1(1 < 1)將狀態i ii的第j jj為置為1得到下一步的狀態 d p[ i][k ]+ma p[k] [j ]dp[i][k] + map[k][j] dp[i][ k]+m ap[k ][j] 表示在當前狀態i中尋找中介點檢查最短路是否可以更新 #include #include #include #include #include using namespace std; intread() while (ss>= '0'&&ss<= '9') return f*x; }const int maxn= 1100010 ;int n,ans= 2e9; int dp[maxn][25 ];int rem[25] [25]; intmain() n<=20的資料範圍在狀壓題中算是開到極限了,蒟蒻擔心卡常所以開了o2,最大的點跑了541ms,目測不開o2也是能過的 9.15——update 再提供一種狀壓搜尋的思路 雖然試了好幾次都卡不過最後乙個點 所以僅供參考學習吧,因為這種思路也挺常用的 dp陣列含義依然同上, 初始d p[ 1][1 ]= 0dp[1][1]=0 dp[1][ 1]=0 搜尋具體**,應該不難理解 dfs( int x, int u) //x是當前狀態,u是當前到達的結點 }最終答案判斷方法與上述dp相同 雖然這種方法艹不過此題,但建議要理解這種思路 #include #include #include #include #include using namespace std; typedef double dd; intread() while (ss>= '0'&&ss<= '9') return f*x; }const int maxn= 1050000 ;int n,ans= 2e9; int rem[22] [22],dp[maxn][22 ];void dfs( int x, int u) }int main() 某鄉有n個村莊 1 輸入格式 村莊數n和各村之間的路程 均是整數 輸出格式 最短的路程。輸入樣例 1 複製3 0 2 1 1 0 2 2 1 0 輸出樣例 1 複製3 輸入解釋 3 0 2 1 1 0 2 2 1 0 這道題卡常卡的太極限了 include include include inclu... 題目描述 某鄉有n個村莊 1分析 n很小,而且哪個村去過與沒去過都可以用二進位制1,0表示,於是容易想到狀壓dp。接下來分析狀態。首先有2n種方案,所有dp狀態中要有一維 1 include include includeusing namespace std typedef long long l... 用乙個數i的二進位制表示某一位的村莊是否已經去過,dp i j 表示當前狀態i,這一次去的村莊是j的最短路程。然後就列舉i j k k表示下乙個去的村莊 然後在if判斷是否符合條件後,用dp i j 更新dp i 1 k 1 k 注意邊界的處理。1 include2 using namespace ...for
#include
void
#include
洛谷 P1171 售貨員的難題 狀壓dp
洛谷P1171 售貨員的難題(狀壓DP)
洛谷 P1171 售貨員的難題(狀壓dp)