題目描述
某鄉有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中尋找中介點檢查最短路是否可以更新
n<=20的資料範圍在狀壓題中算是開到極限了,蒟蒻擔心卡常所以開了o2,最大的點跑了541ms,目測不開o2也是能過的#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()
9.15——update
再提供一種狀壓搜尋的思路
雖然試了好幾次都卡不過最後乙個點
所以僅供參考學習吧,因為這種思路也挺常用的
dp陣列含義依然同上,
初始d p[
1][1
]=
0dp[1][1]=0
dp[1][
1]=0
搜尋具體**,應該不難理解
最終答案判斷方法與上述dp相同void
dfs(
int x,
int u)
//x是當前狀態,u是當前到達的結點
}
雖然這種方法艹不過此題,但建議要理解這種思路
#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 ...