Codeves 2800 送外卖 状态压缩DP+floyd
送外卖
题目描述 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
题解:
看到n的范围就该是状压DP
先跑一遍floyd,
设定dp[i][j] 为当前点i状态为J(所有点是否走过的状态) 的最短路
那么我们枚举状态,起点,终点,转移就好了
#include <iostream> #include <cstdio> #include <cmath> #include <cstring> #include <algorithm> using namespace std; const int N = 20, M = 30005, mod = 1e9+7, inf = 0x3f3f3f3f; typedef long long ll; //不同为1,相同为0 int dp[N][1<<16],ed,n; int f[N][N]; int main() { scanf("%d",&n); for(int i=0;i<=n;i++) { for(int j=0;j<=n;j++) { scanf("%d",&f[i][j]); } } memset(dp,127/3,sizeof(dp)); for(int k=0;k<=n;k++) { for(int i=0;i<=n;i++) { for(int j=0;j<=n;j++) { f[i][j] = min(f[i][j],f[i][k]+f[k][j]); } } } dp[0][0] = 0; ed = (1<<(n+1)) - 1; for(int i=0;i<=ed;i++) { for(int j = 0; j <= n; j++) { for(int k = 0; k <= n; k++) { if((i|(1<<j))!=i) continue; dp[j][i] = min(dp[j][i], dp[k][i - (1<<j)] + f[k][j]); dp[j][i] = min(dp[j][i], dp[k][i] + f[k][j]); } } } printf("%d\n",dp[0][ed]); return 0; }