状压DP (Floyd+状态压缩 )——Hie with the Pie( POJ 3311 )

来源:互联网 发布:超牛数据恢复软件正版 编辑:程序博客网 时间:2024/05/11 22:21
  • 题目链接:
    http://poj.org/problem?id=3311

  • 分析:
    给出n个点,标号从1到n,再给出一个(n+1)*(n+1)大小的矩阵,表示从i到j的花费时间,0代表出发点,从0出发,最后需要回到0,每个点必须都去过,可以重复走,求最短时间。

  • 题解:
    1.先Floyd求一遍两点间最短路:

void Floyd(){    for(int k=0;k<=n;k++)    {        for(int i=0;i<=n;i++)        {            for(int j=0;j<=n;j++)            {                if(dis[i][k] + map[k][j] < dis[i][j])                  dis[i][j] = dis[i][k] + map[k][j];            }        }    }}

2.用一个二进制数,1代表去过这个点,0代表没去过,遍历所有状态下,从0位置出发,遍历每一个出发点和它能抵达的点是否存在更短花时:
dp[i][j]表示i状态下最后抵达j点的最短花时。

void solve(){    memset(dp, -1, sizeof(dp));    dp[1][0] = 0;    for(int i=1; i<(1<<n+1); i++)    {//遍历每一个点去过和没去过的状态        i = i|1;//第一个位置是起点所以或上1        for(int j=0;j<=n;j++)        {            if(dp[i][j]!=-1)//如果抵达了j点            {                for(int k=0;k<=n;k++)                {                    if(k!=j && ( dp[(1<<k)|i][k] == -1 || dp[(1<<k)|i][k] > dp[i][j] + dis[j][k]))                      dp[(1<<k)|i][k] = dp[i][j] + dis[j][k];                }            }        }    }    cout << dp[(1<<(n+1))-1][0] << endl;}
  • AC代码:
#include <iostream>#include <cstdio>#include <cstring>#include <cmath>#include <string>using namespace std;int n;int map[12][12];int dis[12][12];int dp[(1<<12)][12];void Floyd(){    for(int k=0;k<=n;k++)    {        for(int i=0;i<=n;i++)        {            for(int j=0;j<=n;j++)            {                if(dis[i][k] + map[k][j] < dis[i][j])                  dis[i][j] = dis[i][k] + map[k][j];            }        }    }}void solve(){    memset(dp, -1, sizeof(dp));    dp[1][0] = 0;    for(int i=1; i<(1<<n+1); i++)    {        i = i|1;        for(int j=0;j<=n;j++)        {            if(dp[i][j]!=-1)            {                for(int k=0;k<=n;k++)                {                    if(k!=j && ( dp[(1<<k)|i][k] == -1 || dp[(1<<k)|i][k] > dp[i][j] + dis[j][k]))                      dp[(1<<k)|i][k] = dp[i][j] + dis[j][k];                }            }        }    }    cout << dp[(1<<(n+1))-1][0] << endl;}int main(){    while(~scanf("%d", &n) && n)    {        for(int i=0;i<=n;i++)        {            for(int j=0;j<=n;j++)            {                   scanf("%d", &map[i][j]);                dis[i][j] = map[i][j];            }        }        Floyd();        solve();    }    return 0;}
0 0