洛谷P1171 售貨員的難題 狀壓DP

2021-08-15 16:59:58 字數 3790 閱讀 7418

題目描述

某鄉有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的思想

具體**:

for

(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

#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

搜尋具體**,應該不難理解

void

dfs(

int x,

int u)

//x是當前狀態,u是當前到達的結點

}

最終答案判斷方法與上述dp相同

雖然這種方法艹不過此題,但建議要理解這種思路

#include

#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()

洛谷 P1171 售貨員的難題 狀壓dp

某鄉有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...

洛谷P1171 售貨員的難題(狀壓DP)

題目描述 某鄉有n個村莊 1分析 n很小,而且哪個村去過與沒去過都可以用二進位制1,0表示,於是容易想到狀壓dp。接下來分析狀態。首先有2n種方案,所有dp狀態中要有一維 1 include include includeusing namespace std typedef long long l...

洛谷 P1171 售貨員的難題(狀壓dp)

用乙個數i的二進位制表示某一位的村莊是否已經去過,dp i j 表示當前狀態i,這一次去的村莊是j的最短路程。然後就列舉i j k k表示下乙個去的村莊 然後在if判斷是否符合條件後,用dp i j 更新dp i 1 k 1 k 注意邊界的處理。1 include2 using namespace ...