Poj 3311 Hie with the Pie【Floyd+状压dp】

来源:互联网 发布:致远软件招聘 编辑:程序博客网 时间:2024/05/23 11:45

Hie with the Pie

Time Limit: 2000MS

 

Memory Limit: 65536K

Total Submissions: 6180

 

Accepted: 3330

Description

The Pizazz Pizzeria prides itself in delivering pizzas to its customers as fast as possible. Unfortunately, due to cutbacks, they can afford to hire only one driver to do the deliveries. He will wait for 1 or more (up to 10) orders to be processed before he starts any deliveries. Needless to say, he would like to take the shortest route in delivering these goodies and returning to the pizzeria, even if it means passing the same location(s) or the pizzeria more than once on the way. He has commissioned you to write a program to help him.

Input

Input will consist of multiple test cases. The first line will contain a single integer n indicating the number of orders to deliver, where 1 ≤ n ≤ 10. After this will be n + 1 lines each containing n + 1 integers indicating the times to travel between the pizzeria (numbered 0) and the n locations (numbers 1 to n). The jth value on the ith line indicates the time to go directly from location i to location j without visiting any other locations along the way. Note that there may be quicker ways to go from i to j via other locations, due to different speed limits, traffic lights, etc. Also, the time values may not be symmetric, i.e., the time to go directly from location i to j may not be the same as the time to go directly from location j to i. An input value of n = 0 will terminate input.

Output

For each test case, you should output a single number indicating the minimum time to deliver all of the pizzas and return to the pizzeria.

Sample Input

3

0 1 10 10

1 0 1 2

10 1 0 10

10 2 10 0

0

Sample Output

8

Source

East Central North America 2006

 

题目大意:一共有n个地方要去,0号节点作为起点,派送员需要从起点出发,选择一条路径,经过所有节点,然后再回到源点,问最少路径花费。


思路:


1、求一遍最短路。


2、

建设dp【i】【j】数组,表示i状态要终点是j的最短距离。构建思路是这样的:



要从i状态变成q状态,无非要从i状态中找一个点j,然后在q状态中找到一个点k,从j走到k。

辣么状态转移方程不难推出:
dp【q】【k】=min(dp【q】【k】,dp【i】【j】+dis【j】【k】)其中q一定是从i+(1 <<k)来的。

整个状态转移方程其实就是在表示从i状态中找一个点j,再选一个i状态中没有走过的点k,从j走到k。


辣么要从i状态变成q状态之前呢,要满足这样两个条件:


1、i状态里边有j这个点,才能把j这个点确定下来,辣么我们要怎样确定i状态有没有j这个点呢?根据位运算里边&运算符的操作规则:同1为1,其余为0的特性,我们就可以用

i&(1<<j)判断其值是否为0即可,如果为0,表示i状态中没有走过j(也就是i状态中没有j这个点),如果不为0,那么就表示有。

2、i状态里边没有k这个点,才能把k这个点确定下来,判断方法同上。

注意的点:位运算优先级很难记,不妨在有位运算的地方都加上括号。


AC代码:


#include<stdio.h>#include<iostream>#include<algorithm>#include<string.h>using namespace std;int map[15][15];int dp[1<<13][15];int main(){    int n;    while(~scanf("%d",&n))    {        if(n==0)break;        memset(dp,0x3f3f3f3f,sizeof(dp));        for(int i=0;i<=n;i++)        {            for(int j=0;j<=n;j++)            {                scanf("%d",&map[i][j]);            }        }        for(int i=0;i<=n;i++)        {            for(int j=0;j<=n;j++)            {                for(int k=0;k<=n;k++)                {                    map[j][k]=min(map[j][k],map[j][i]+map[i][k]);                }            }        }        int end=(1<<(n+1));        dp[1][0]=0;        for(int i=0;i<end;i++)        {            for(int j=0;j<=n;j++)            {                if (!(i&(1<<j))) continue;                for(int k=0;k<=n;k++)                {                    if (i&(1<<k)) continue;                    int q=(i+(1<<k));                    dp[q][k]=min(dp[q][k],dp[i][j]+map[j][k]);                }            }        }        int output=0x3f3f3f3f;        for(int i=1;i<=n;i++)        {            output=min(output,map[i][0]+dp[end-1][i]);        }        printf("%d\n",output);    }}






0 0
原创粉丝点击