A、收集纸片
状态压缩dp
)当初小白赛可以过这道题,是因为前几天做过一题比较类似的小松鼠找松果的题目……
回到这个题目,题目给出的地图很小最大也就是可以考虑二进制枚举。
那么就开一个数组代表以为终点把二进制表示中的1走过一遍的最小花费。
那么第一步预处理每两个点之间的距离,以及和源点之间的距离。
初始化只走一个点的值为从源点去对应点的起始花费。
再去二进制枚举我能选择的终点全部的情况,对于枚举的状态来说,如果有一个点我可以去,那么从这个点开始更新各个我这次不打算去的终点,因为我要搜集全部的纸片,相当于枚举决策点k。
最后再把从最终留在位置花费加上回去起点花费,取最小值就是题目要求的。
#include <bits/stdc++.h> using namespace std; const int INF = 1 << 20; const int N = 25; const int M = 65536; int x[N], y[N]; int maps[N][N]; int dp[N][M]; int maxz; //状态压缩dp void updata(int& x, int y) { if (x > y) x = y; } int main() { ios::sync_with_stdio(false); int t; cin >> t; while (t--) { int n, m; cin >> n >> m; cin >> x[0] >> y[0]; int num; cin >> num; for (int i = 1; i <= num; ++i) cin >> x[i] >> y[i]; for (int i = 0; i <= num; ++i) for (int j = 0; j <= num; ++j) maps[i][j] = abs(x[i] - x[j]) + abs(y[i] - y[j]); maxz = (1 << num) - 1; for (int i = 0; i <= maxz; ++i) for (int j = 0; j <= num; ++j) dp[j][i] = INF; for (int i = 1; i <= num; ++i) dp[i][1 << (i - 1)] = maps[0][i]; for (int i = 0; i <= maxz; ++i) { for (int j = 1; j <= num; ++j) if (i & (1 << (j - 1))) { for (int k = 1; k <= num; ++k) if (!(i & (1 << (k - 1)))) updata(dp[k][i + (1 << (k - 1))], dp[j][i] + maps[j][k]); } } int ans = INF; for (int i = 1; i <= num; ++i) updata(ans, dp[i][maxz] + maps[0][i]); cout << "The shortest path has length " << ans << endl; } return 0; }