题目描述
房间里放着 n 块奶酪。一只小老鼠要把它们都吃掉,问至少要跑多少距离?老鼠一开始在 (0,0) 点处。
 输入格式
第一行有一个整数,表示奶酪的数量 n。
第 2 到第 (n+1) 行,每行两个实数,第 (i+1) 行的实数分别表示第 i 块奶酪的横纵坐标 xi,yi。
 输出格式
输出一行一个实数,表示要跑的最少距离,保留 2 位小数。
 思路:状态压缩dp(状压dp)
 使用状压dp原因
- 数据量小(n≤15)
- 可以使用一个整数表达一个访问过的点的集合
 基本定义
将访问过的数($a, b, c, \cdots $)定义为状态 state=2a+2b+2c+⋯,定义第 i 个点到第 j 个点的距离为 dis(i,j)。
| 1
 | state = (1 << a) + (1 << b) + (1 << c) + ...
 | 
 dp表
dp[i][state]→ 访问过状态为 state 的点之后,到达第 i 个点的最小距离(0≤i≤n,1≤state≤2n+1−1)。说明:将原点看成第 0 个点,所以 i 可以取 0,state 的有效值仅为奇数(必定过原点),当 0∼n 位全部为 1 时取最大值 2n+1−1。
 状态
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 
 | #include <bits/stdc++.h>
 
 using namespace std;
 using ll = long long;
 
 inline void minset(double &t, double other) {
 t = min(t, other);
 }
 
 inline void maxset(double &t, double other) {
 t = max(t, other);
 }
 
 struct pos {
 double x, y;
 };
 
 const int inf = 0x7f7f7f7f;
 
 const int N = 17;
 
 int n;
 
 pos p[N];
 
 double dp[N][1 << N];
 
 inline double sq(double d){
 return d * d;
 }
 
 inline double dis(int from, int to){
 return sqrt(sq(p[from].x - p[to].x) + sq(p[from].y - p[to].y));
 }
 
 inline bool vis(int state, int target){
 return (state & (1 << target));
 }
 
 int main() {
 cin >> n;
 for(int i = 1; i <= n; i++) {
 cin >> p[i].x >> p[i].y;
 }
 memset(dp, inf, sizeof dp);
 for(int i = 1; i <= n; i++) {
 dp[i][1] = dis(0, i);
 }
 for(int state = 1; state < (1 << (n + 1)); state += 2){
 for(int i = 1; i <= n; i++) {
 if(!vis(state, i)){
 for(int j = 0; j <= n; j++) {
 if(i == j) continue;
 if(vis(state, j)) continue;
 minset(dp[i][state | (1 << j)], dis(i, j) + dp[j][state]);
 
 }
 }
 }
 }
 double minv = inf;
 const int all_vis_state = (1 << (n + 1)) - 1;
 for(int i = 1; i <= n + 1; i++){
 int c_state = all_vis_state - (1 << i);
 minset(minv, dp[i][c_state]);
 }
 cout << fixed << setprecision(2) << minv << endl;
 return 0;
 }
 
 | 
 补充
 保留两位小数的两种做法
- printf("%.2lf", x);
- cout << fixed << setprecision(2) << x;