一、状态压缩dp(2)送披萨

来源:互联网 发布:平台优化方案 编辑:程序博客网 时间:2024/06/06 04:17
2、 送披萨(pie)
【问题描述】
披萨店为其能尽可能快地将披萨送到顾客手中感到骄傲。不幸的是,由于削减开支,现在他
们只能雇佣一个司机来送披萨。这个司机在送披萨之前,要等 1 个或多个(最多 10 个)要
处理的订单。司机希望送货和返回披萨店能走最短的路线,即使路上会走过同一地点或经过
披萨店多次。现在请你编写一个程序来帮助这个司机。
【输入格式】
输入由多个测试用例组成。第一行给出一个整数 n,表示要送货的订单数,1<=n<=10。然后
n+1 行,每行给出 n+1 个整数,表示披萨店(编号为 0)和 n 个地点(编号从 1 n)之
间到达所用的时间。在第 i 行的第 j 个值表示从地点 i 直接到地点 j,在路上不去其他地点的
时间。注意,由于不同的速度限制和红绿灯,从 i j 通过其他地点可能会比直接走更快;
而且,时间值可能不对称,也就是说,直接从地点 i j 所用的时间可能和从地点 j 到地点 i
所用的时间不一样。输入以 n=0 终止。
【输出格式】
对每个测试用例,输出一个数,表示送完所有的披萨并返回披萨店所用的最少时间。
【输入样例】

3

0 1 10 10
1 0 1 2
10 1 0 10
10 2 10 0
0
【输出样例】
8


分析:

可以用全排列做,求出一个最短的距离即可。或者用状态压缩DP.用一个二进制数表示城市是否走过

【状态表示】dp[state][i]表示到达i点状态为state的最短距离

【状态转移方程】dp[state][i] =min{dp[state][i],dp[state'][j]+dis[j][i]} dis[j][i]为j到i的最短距离

【DP边界条件】dp[state][i] =dis[0][i]  state是只经过i的状态


代码:

#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使得距离更短
                        } 
                    } 
                } 
            } 
       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; 
}

1 0