题目大意&链接
有 n 块奶酪,小老鼠从 (0, 0) 点出发,要吃掉所有奶酪,求跑过的最少距离。
输入输出:输入为奶酪数量 n 以及每块奶酪的横、纵坐标 xi, yi;输出为保留两位小数的最少跑动距离。
输入输出样例:
输入:
4
1 1
1 -1
-1 1
-1 -1
输出:
7.41
详情:luogu_P1433
解题思路
状态压缩与记忆化搜索:
状态表示:使用 pos 表示当前所在奶酪的索引,deep 表示已吃奶酪的数量,len 表示已跑过的距离,path 是一个整数,通过位运算(状态压缩)记录已经访问过的奶酪(每一位代表一块奶酪是否被访问 )。
记忆化:dp[pos][path] 存储从当前状态(在 pos 号奶酪位置、已访问 path 对应奶酪集合 )出发,吃完剩余奶酪所需的最短距离增量。避免重复计算相同状态,大幅减少递归次数。
AC代码附上
#include <bits/stdc++.h> using namespace std;
const int N = 20; int n;
double a[N][2];
bool st[N];
double dp[N][1 << 16];
double dfs(int pos, int deep, double len, int path) { double ans = 1e9 + 10; if(deep == n) return len; if(dp[pos][path]) return len + dp[pos][path]; for(int i = 1; i <= n; i++) { if(st[i]) continue; st[i] = 1; double r1 = a[i][0] - a[pos][0]; double r2 = a[i][1] - a[pos][1]; double r = sqrt(r1 * r1 + r2 * r2); ans = min(ans, dfs(i, deep + 1, len + r, path | (1 << i))); st[i] = 0; } dp[pos][path] = ans - len; return ans; }
int main() { cin >> n; for(int i = 1; i <= n; i++) cin >> a[i][0] >> a[i][1]; printf("%.2lf", dfs(0, 0, 0, 0)); return 0; }
|