codevs2800 送外卖

 

题目描述 Description

有一个送外卖的,他手上有n份订单,他要把n份东西,分别送达n个不同的客户的手上。n个不同的客户分别在1~n个编号的城市中。送外卖的从0号城市出发,然后n个城市都要走一次(一个城市可以走多次),最后还要回到0点(他的单位),请问最短时间是多少。现在已知任意两个城市的直接通路的时间。

输入描述 Input Description

第一行一个正整数n (1<=n<=15)

接下来是一个(n+1)*(n+1)的矩阵,矩阵中的数均为不超过10000的正整数。矩阵的i行j列表示第i-1号城市和j-1号城市之间直接通路的时间。当然城市a到城市b的直接通路时间和城市b到城市a的直接通路时间不一定相同,也就是说道路都是单向的。

输出描述 Output Description

一个正整数表示最少花费的时间

样例输入 Sample Input
3
0 1 10 10
1 0 1 2
10 1 0 10
10 2 10 0
样例输出 Sample Output

8

数据范围及提示 Data Size & Hint

1<=n<=15

分类标签 Tags 

 
 
正解:状态压缩DP
解题报告:
  以前一直没打过状压DP,今天打道水题。。。
  显然做之前要floyd预处理出两点之间的最短路。
  然后f[i][s]表示到达i时状态为s的最短路径长度,枚举状态和每次走的两个点就可以了。状态s是一个二进制的方法(状压不都这样吗)
  为什么提前算出最短路是可行的呢?因为显然w[i][j]表示i和j的最短路径,那么至少可以保证经过i和j,即便中间经过了其他的点,也没有关系,反正我们会经过的,所以并不会有问题。
 
 1 //It is made by jump~
 2 #include <iostream>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <cstdio>
 6 #include <cmath>
 7 #include <algorithm>
 8 #include <ctime>
 9 #include <vector>
10 #include <queue>
11 #include <map>
12 #include <set>
13 #ifdef WIN32   
14 #define OT "%I64d"
15 #else
16 #define OT "%lld"
17 #endif
18 using namespace std;
19 typedef long long LL;
20 const int MAXN = 16;
21 const int MAXS = (1<<17);
22 int n;
23 int w[MAXN][MAXN];
24 int f[MAXN][MAXS];//f[i][j]表示到达i时状态为j的最小值
25 
26 inline int getint()
27 {
28        int w=0,q=0;
29        char c=getchar();
30        while((c<'0' || c>'9') && c!='-') c=getchar();
31        if (c=='-')  q=1, c=getchar();
32        while (c>='0' && c<='9') w=w*10+c-'0', c=getchar();
33        return q ? -w : w;
34 }
35 
36 inline void solve(){
37     n=getint();
38     for(int i=0;i<=n;i++)
39     for(int j=0;j<=n;j++)
40         w[i][j]=getint();
41     for(int k=0;k<=n;k++)//预处理出最短路
42     for(int i=0;i<=n;i++)
43         for(int j=0;j<=n;j++)
44         w[i][j]=min(w[i][j],w[i][k]+w[k][j]);
45     int end=(1<<(n+1))-1;
46     memset(f,127/3,sizeof(f)); f[0][0]=0; f[0][1]=0;
47     for(int i=0;i<=end;i++)//此时状态为i,从from到now
48     for(int now=0;now<=n;now++)
49         for(int from=0;from<=n;from++) {
50         if(from==now) continue;
51         if( ( (1<<now) | i ) !=i) continue;//当前状态必须要经过i
52         f[now][i]=min(f[now][i],f[from][i-(1<<now)]+w[from][now]);//之前没到达过now
53         f[now][i]=min(f[now][i],f[from][i]+w[from][now]);//之前已经到达过now
54         }
55     printf("%d",f[0][end]);
56 }
57 
58 int main()
59 {
60   solve();
61   return 0;
62 }

 

 
 
posted @ 2016-07-08 11:52  ljh_2000  阅读(318)  评论(0编辑  收藏  举报