首先求出各点之间的最短路,floyed即可,注意是0~n。
然后考虑状压,f[i][j]表示状态为i时访问j点时的最短路和,1表示访问,0表示未访问,然后第j个点所在的位置就是(1<<j)有0存在,例如状态1010,从右至左,点1.3被访问,所以我们要处理第1各点就是(1<<1)。
f[i][j]=min(f[i][j],f[i-(1<<j)][p]+dis[p][j]);
p表示枚举每个点,i-(1<<j)状态回到访问j之前,很详细了。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 int n,ans; 6 int dp[(1<<16)][16],dis[16][16]; 7 int main() 8 { 9 scanf("%d",&n); 10 ans=0x7fffffff; 11 memset(dp,127,sizeof(dp)); 12 for (int i=0;i<=n;i++) 13 for (int j=0;j<=n;j++) 14 scanf("%d",&dis[i][j]); 15 for (int k=0;k<=n;k++) 16 for (int i=0;i<=n;i++) 17 for (int j=0;j<=n;j++) 18 dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]); 19 dp[0][0]=0; 20 for (int i=0;i<(1<<(n+1));i++) 21 for (int now=0;now<=n;now++) 22 for (int last=0;last<=n;last++) 23 if (i&(1<<now)) 24 dp[i][now]=min(dp[i][now],dp[i-(1<<now)][last]+dis[last][now]); 25 for (int i=0;i<=n;i++) 26 ans=min(ans,dp[(1<<(n+1))-1][i]+dis[i][0]); 27 printf("%d\n",ans); 28 return 0; 29 }
题目描述
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