POJ 3311 Hie with the Pie(Floyd + 状压dp)

来源:互联网 发布:鳄鱼皮 知乎 编辑:程序博客网 时间:2024/05/17 07:30

思路:

  • 首先要求出多源最短路,floyd直接上
  • 然后是我们要求的,哈密顿回路的一个变种,咱们的题目要求的是把每个点都走一遍回到起点,但是与哈密顿回路不同的是,每个点可以走多次。(所以可以用floyd先把所有边都压缩一边)
  • 所以我们需要一个代表状态的数,本题最多11个点,所以我们至少需要11位的二进制数来表示。第i位代表着第i个节点是否已经走过。
  • 除了需要已经走过的信息,我们还需知道当前的位置,所以加一维。dp[s][i]表示在s的状态下,当前在i点所走的最短距离。

AC代码:

#include <iostream>#include <cstdio>#include <algorithm>#include <string.h>#include <vector>using namespace std;int n;int dp[(1L<<11)+10][14];int a[22][22];void floyd(){    for(int k = 0;k <= n;k++){        for(int i = 0;i <= n;i++){            for(int j = 0;j <= n;j++){                if(a[i][j] > a[i][k] + a[k][j]){                    a[i][j] = a[i][k] + a[k][j];                }            }        }    }}int main(){    while(~scanf("%d",&n),n){        for(int i = 0;i <= n;i++){            for(int j = 0;j <= n;j++){                scanf("%d",&a[i][j]);            }        }        floyd();        int flag = (1<<(n+1)) - 1;        memset(dp,0x3f,sizeof(dp));        for(int i = 0;i <= n;i++){//边界条件            dp[1][i] = a[0][i];//dp[0][i]是不能走到的,所以赋无穷大        }        int s;        for(s = 1;s <= flag;s++){            for(int i = 0;i <=n;i++){                if(s == (1<<i)) dp[s][i] = a[0][i];//边界条件,但其实这种状态并不符合条件,只是要作为边界                for(int j = 0;j <=n;j++){                    if(i!=j && (s&(1<<j)))                        dp[s][i] = min(dp[s&(~(1<<j))][j]+a[j][i],dp[s][i]);                }            }        }        int ans = 0x7f7f7f7f;        for(int i = 0;i <= n;i++){            ans = min(ans,dp[s-1][i]+a[i][0]);        }        printf("%d\n",ans);    }    return 0;}
0 0