poj 3311 Hie with the Pie
题意:有n个城市和一个披萨店(0),给出一个(n+1)阶的矩阵,表示 i 到 j 的距离,每个点可走多次。求从披萨店出发,再回到披萨店,把每个城市走一遍要走的最近距离。
状态DP,状态s二进制中第几位表示第几个城市走没走过的状态,0表示每走过,1表示走过。
先用Floyd求任意两点之间的最近距离,然后状态s从0开始到 (1<<n)-1,求dp[s][i],dp[s][i]表示状态s时,走到城市 i 时的最近距离。最后再求 (dp[(1<<n)-1][i]+map[i][0])的最小值。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<stdio.h> #include<string.h> #define min(a,b) (a)>(b)?(b):(a) const int inf = 99999999; int n; int map[15][15]; int dp[1200][15]; void Input() { for(int i=0;i<=n;i++) for(int j=0;j<=n;j++) scanf("%d",&map[i][j]); } void Floyd() { for(int k=0;k<=n;k++) for(int i=0;i<=n;i++) for(int j=0;j<=n;j++) if(map[i][j]>map[i][k]+map[k][j]) map[i][j]=map[i][k]+map[k][j]; } void Deal() { for(int s=0;s<(1<<n);s++) { for(int i=1;i<=n;i++) { if(s & (1<<(i-1))) { if(s==(1<<(i-1))) dp[s][i]=map[0][i]; else { dp[s][i]=inf; for(int j=1;j<=n;j++) if(s & (1<<(j-1)) && j!=i) dp[s][i]=min(dp[s][i],dp[s^(1<<(i-1))][j]+map[j][i]); } } } } int ans; int stat=(1<<n)-1; ans=dp[stat][1]+map[1][0]; for(int i=2;i<=n;i++) ans=min(ans,dp[stat][i]+map[i][0]); printf("%d\n",ans); } int main() { while(scanf("%d",&n) && n) { memset(dp,0,sizeof(dp)); Input(); Floyd(); Deal(); } return 0; }