现在的位置: 首页 > 综合 > 正文

poj 3311

2015年02月08日 ⁄ 综合 ⁄ 共 1633字 ⁄ 字号 评论关闭

//Floyd + 状态压缩DP
//题意是有N个城市(1~N)和一个PIZZA店(0),要求一条回路,从0出发,又回到0,而且距离最短
//也就是TSP(旅行商)问题,首先不难想到用FLOYD先求出任意2点的距离dis[i][j]
//接着枚举所有状态,用11位二进制表示10个城市和pizza店,1表示经过,0表示没有经过
//定义状态DP(S,i)表示在S状态下,从0开始到达城市I的最优值
//接着状态转移方程:DP(S,i) = min{DP(S^(1<<i-1),k) + dis[k][j],DP(S,i)},器重S^(1<<i-1)表示未到达城市i的所有状态,1<=k<=n
//对于全1的状态,即S = (1<<n)-1则表示经过所有城市的状态,最终还需要回到PIZZA店0
//那么最终答案就是min{DP(S,i) + dis[i][0]}
#include<iostream>
#define INF 100000000
using namespace std;
int dis[12][12];
int dp[1<<11][12];
int n,ans,_min;
int main()
{
    //freopen("in.txt","r",stdin);
    while(scanf("%d",&n) && n)
    {
        for(int i = 0;i <= n;++i)
            for(int j = 0;j <= n;++j)
                scanf("%d",&dis[i][j]);
        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] + dis[k][j] < dis[i][j])
                        dis[i][j] = dis[i][k] + dis[k][j];
        
        for(int S = 0;S <= (1<<n)-1;++S)//枚举所有状态,用位运算表示
            for(int i = 1;i <= n;++i)
            {
                if(S & (1<<(i-1)))//状态S中已经过城市i
                {
                    if(S == (1<<(i-1)))    dp[S][i] = dis[0][i];//状态S只经过城市I,最优解自然是从0出发到i的dis,这也是DP的边界
                    else//如果S有经过多个城市
                    {
                        dp[S][i] = INF;//注意一下在这赋初值
                        for(int j = 1;j <= n;++j)
                        {
                            if(S & (1<<(j-1)) && j != i)//枚举不是城市I的其他城市
                                dp[S][i] = min(dp[S^(1<<(i-1))][j] + dis[j][i],dp[S][i]);
                            //在没经过城市I的状态中,寻找合适的中间点J使得距离更短,和FLOYD一样
                        }
                    }
                }
            }
        ans = dp[(1<<n)-1][1] + dis[1][0];
        for(int i = 2;i <= n;++i)
            if(dp[(1<<n)-1][i] + dis[i][0] < ans)
                ans = dp[(1<<n)-1][i] + dis[i][0];
        printf("%d/n",ans);
    }
    return 0;
}

抱歉!评论已关闭.