poj3311——Hie with the Pie——————【状态压缩、TSP旅行商问题】

/**

   解题思路:首先预处理出来各个点间的最小距离,然后dp求解。定义状态dp[i][j]代表当前访问过的城市用十进制表示为i,最终停留在j城市所走的最短距离。初始化dp[1][0]=0,状态值i所表示的二进制的2的零次方为1表示城市0被已经经过,状态值代表的二进制的2的m次方为1表示城市m已经经过。

*/

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>
using namespace std;
#define INF 0x3f3f3f3f
int d[12][12];                  //用以记录两点间的最短距离
int n,top;
int dp[1<<12][12];              //dp[i][j]代表状态值为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(d[i][k]<INF&&d[k][j]<INF)    //松弛操作
                d[i][j]= d[i][j]<(d[i][k]+d[k][j])?d[i][j]:(d[i][k]+d[k][j]);
            }
        }
    }
}
void DP(){

    top=1<<(n+1);       //状态值的最大值
    memset(dp,-1,sizeof(dp));   //初始化为非法
    dp[1][0]=0;                 //只经过0位置,距离初始化为0
    for(int i=0;i<top;i++){     //枚举状态值

        i=i|1;                  //哪种状态都必经过0位置,因为0是起点位置
        for(int j=0;j<=n;j++){  //枚举所有城市

            if(dp[i][j]!=-1){   //枚举该状态值下到达j城市时的最短距离

                for(int k=0;k<=n;k++){
                    //枚举该状态值下从当前城市j到达其他城市k
                    if((k!=j)&&(dp[i|(1<<k)][k]==-1||dp[i|(1<<k)][k]>dp[i][j]+d[j][k])){
                        //如果j和k不冲突,且该城市未访问过,或已访问过但是没有从j到k近
                        //状态转移。如果状态值并未发生改变,说明最后回到的城市是原状态中包含的城市
                        dp[i|(1<<k)][k]=dp[i][j]+d[j][k];
                    }
                }
            }
        }
    }
}
int main(){

    while(scanf("%d",&n)!=EOF&&n){

        for(int i=0;i<=n;i++){

            for(int j=0;j<=n;j++){

                int tmp;
                scanf("%d",&tmp);
                d[i][j]=tmp;
            }
        }
        floyd();                //floyd求出各个点间的最短距离
        DP();         
        printf("%d\n",dp[top-1][0]);//top-1代表n个城市都走完的状态,0代表最后回到了pizzeria
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值