战鹰每天早上需要到取货点取货,接着将所有快递送至配送点,最后再回到自己的家。 我们可以将其中的所有地点视为 n个点,其中第1个点表示取货点,第n个点表示战鹰的家,第2至n−1个点表示快递的配送点。 经过几天的配送,战鹰已经知道从点i到点j所需要的时间了。由于战鹰还要准备晚上的直播,战鹰想要以最短的时间配送完所有快递并回到家。 目前战鹰已经在取货点了,你能告诉战鹰她最短需要多少时间才能配送完所有快递并回到家吗? 第一行一个整数n。接下来n行每行n个整数,其中第i行第j个整数表示从点i到点j 需要的时间(记为a[i,j] )对于任意的x,y,z ,数据保证a[x,x]=0,a[x,y]=a[y,x] 并且a[x,y]+a[y,z]>=a[x,z]一个整数,表示战鹰配送完所有快递并回到家所需要的最短时间,生成C++代码,运行时间限制为1000ms,使用状态压缩DP思想。
时间: 2024-02-06 21:11:03 浏览: 11
以下是使用状态压缩DP思想实现的C++代码:
```c++
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 18;
const int INF = 1e9;
int n, a[MAXN][MAXN], dp[1 << MAXN][MAXN];
int main() {
cin >> n;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
cin >> a[i][j];
}
}
memset(dp, 0x3f, sizeof(dp)); // 初始化为无穷大
dp[1][0] = 0; // 起点为0号节点
// 状态压缩DP
for (int s = 1; s < (1 << n); s++) {
for (int i = 0; i < n; i++) {
if (s & (1 << i)) {
for (int j = 0; j < n; j++) {
if (i != j && (s & (1 << j))) {
dp[s][i] = min(dp[s][i], dp[s - (1 << i)][j] + a[j][i]);
}
}
}
}
}
int ans = INF;
for (int i = 1; i < n; i++) {
ans = min(ans, dp[(1 << n) - 1][i] + a[i][0]); // 最后回到起点
}
cout << ans << endl;
return 0;
}
```
思路解析:
本题中的状态为“已经送过快递的配送点的集合”,因此可以使用状态压缩DP来解决。具体地,设dp[s][i]表示已经送过快递的配送点的集合为s,当前所在节点为i时,配送完所有快递并回到家所需要的最短时间。转移方程为:
$$dp[s][i]=\min_{j \in s,j \neq i}\{dp[s-\{i\}][j]+a_{ji}\}$$
表示从已经送过快递的点集s中选择一个点j,将其当作上一个配送点,然后从该点j到当前节点i进行配送,再加上从起点到j的时间,即为dp[s][i]的值。最终答案为:
$$\min_{i=2}^{n-1}\{dp[(2^n-1)-\{1\}][i]+a_{i,1}\}$$
表示从任意一个送完最后一个快递的节点i回到起点0,再加上从起点0到节点i的时间,即为最短时间。