[CODEVS2800] 送外卖
2800 送外卖
时间限制: 2 s
空间限制: 256000 KB
题目等级 : 钻石 Diamond
题目描述 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
提交地址 : CODEVS2800
题解:
先写了一个爆搜20分...
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 6 int n; 7 int G[20][20]; 8 9 int dp[1<<16][16];//在第j个位置,访问状态为i,行走的最小值 10 11 inline int DP(int x, int now) 12 { 13 for (register int i = 1 ; i <= n ; i ++) 14 { 15 if (i == now) continue; 16 if (dp[x|(1<<(i-1))][i] > dp[x][now] + G[now][i]) 17 { 18 dp[x|(1<<(i-1))][i] = dp[x][now] + G[now][i]; 19 // cout << dp[x|(1<<(i-1))][i]<<endl; 20 DP(x|(1<<(i-1)), i); 21 } 22 } 23 24 } 25 26 int main() 27 { 28 cin >> n; 29 n++; 30 for (register int i = 1 ; i <= n ; i ++) 31 for (register int j = 1 ; j <= n ; j ++) 32 scanf("%d", &G[i][j]); 33 memset(dp, 0x3f, sizeof dp); 34 dp[0][n] = 0; 35 DP(0, n); 36 cout << dp[(1<<n)-1][n]; 37 return 0; 38 }
感觉离正解不远了...
果然...
先跑一遍Floyd,求出最短路径;
然后dp[i][j]表示访问状态为i,现在在第j个点的最短行走路程;
然后就瞎dp就行额
Code:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 6 int n; 7 int G[20][20]; 8 int dp[1<<16][16];//在第j个位置,访问状态为i,行走的最小值 9 10 int main() 11 { 12 cin >> n; 13 for (register int i = 0 ; i <= n ; i ++) 14 for (register int j = 0 ; j <= n ; j ++) 15 scanf("%d", &G[i][j]); 16 for (register int k = 0 ; k <= n ; k ++) 17 for (register int i = 0 ; i <= n ; i ++) 18 for (register int j = 0 ; j <= n ; j ++) 19 G[i][j] = min(G[i][j], G[i][k] + G[k][j]); 20 memset(dp, 0x3f, sizeof dp); 21 dp[0][0] = 0; 22 int e = (1 << (n + 1)) - 1; 23 for (register int i = 0 ; i <= e ; i ++) 24 { 25 for (register int j = 0 ; j <= n ; j ++) 26 { 27 for (register int k = 0 ; k <= n ; k ++) 28 { 29 if ((i | (1 << j)) != i) continue;//如果j在枚举的状态里还没有访问过,跳过 30 dp[i][j] = min(dp[i][j], dp[i-(1<<j)][k] + G[k][j]);//j是刚走的 31 dp[i][j] = min(dp[i][j], dp[i][k] + G[k][j]);//j是早就走过的 32 } 33 } 34 } 35 cout << dp[e][0]; 36 return 0; 37 }