1. 程式人生 > >codevs2596 售貨員的難題(狀壓dp)

codevs2596 售貨員的難題(狀壓dp)

樹狀dp min fault 極限 iostream mut 通過 cnblogs 表示

2596 售貨員的難題

時間限制: 1 s 空間限制: 32000 KB 題目等級 : 鉆石 Diamond
題目描述 Description

某鄉有n個村莊(1<n<=15),有一個售貨員,他要到各個村莊去售貨,各村莊之間的路程s(0<s<1000)是已知的,且A村到B村與B村到A村的路大多不同。為了提高效率,他從商店出發到每個村莊一次,然後返回商店所在的村,假設商店所在的村莊為1,他不知道選擇什麽樣的路線才能使所走的路程最短。請你幫他選擇一條最短的路。

輸入描述 Input Description

村莊數n和各村之間的路程(均是整數)

輸出描述 Output Description

最短的路程

樣例輸入 Sample Input

3

0 2 1

1 0 2

2 1 0

樣例輸出 Sample Output

3

數據範圍及提示 Data Size & Hint

本題可用最短路思想、搜索來解決,但是可能無法通過一組極限數據(且效率較低)。建議按樹狀DP考慮

/*
狀壓dp入門題
f[i][j]表示當前狀態為i,走到第j個城市最短路徑 
相應的狀態轉移方程為f[i][j]=min( f[i^(1<<j)][k]+g[k][j]);  
i^(1<<j)的意思是將j這個城市從i狀態中去掉.g[k][j]是k和j之間的距離。 
*/ #include<iostream> #include<cstdio> #include<cstring> #define maxn 50010 using namespace std; int n,g[20][20],f[maxn][20],ans; int min(int x,int y){return x<y?x:y;} int main() { scanf("%d",&n);n--; memset(f,127/3,sizeof(f)); for(int i=0;i<=n;i++)
for(int j=0;j<=n;j++) scanf("%d",&g[i][j]); ans=f[0][0];f[0][0]=0; for(int i=1;i<(1<<n);i++) for(int j=1;j<=n;j++)if(i&(1<<j-1)) for(int k=0;k<=n;k++) f[i][j]=min(f[i][j],f[i^(1<<j-1)][k]+g[k][j]); for(int i=1;i<=n;i++) ans=min(ans,f[(1<<n)-1][i]+g[i][0]); printf("%d\n",ans); return 0; }

codevs2596 售貨員的難題(狀壓dp)