题目描述
房间里放着 nn 块奶酪。一只小老鼠要把它们都吃掉,问至少要跑多少距离?老鼠一开始在 (0,0)(0,0) 点处。
输入格式
第一行有一个整数,表示奶酪的数量 n。
第 2 到第(n+1) 行,每行两个实数,第 (i+1) 行的实数分别表示第 ii 块奶酪的横纵坐标 xi,yi。
输出格式
输出一行一个实数,表示要跑的最少距离,保留 2 位小数。
输入输出样例
输入 #1复制
4 1 1 1 -1 -1 1 -1 -1输出 #1复制
7.41说明/提示
数据规模与约定
对于全部的测试点,保证 1\leq n\leq 151≤n≤15,|x_i|, |y_i| \leq 200∣xi∣,∣yi∣≤200,小数点后最多有 33 位数字。
提示
对于两个点 (x_1,y_1)(x1,y1),(x_2, y_2)(x2,y2),两点之间的距离公式为 \sqrt{(x_1-x_2)^2+(y_1-y_2)^2}(x1−x2)2+(y1−y2)2。
2022.7.132022.7.13:新增加一组 \text{Hack}Hack 数据。
分析,深搜,搜索所有可能,找到最小的那个,但是有一个问题,就是在搜索和回溯时如何找到上一个点,卡在了这里,看了题解,即使不用dp也要用状态压缩,因为还没学到,就着了一个和自己思路相同的相同,代码相似的,摘抄自洛谷题解
#include<stdio.h>
#include<math.h>
using namespace std;
int n;
double a[20],b[20],dp[65000][20];
bool v[20];
double ans=1e9;
double dis(int x,int y){
sqrt((a[x]-a[y])*(a[x]-a[y])+(b[x]-b[y])*(b[x]-b[y]));
}
void dfs(int t,int now,double s,int b){
if(s>ans) return;
if(t==n){
ans=ans<s?ans:s;
return;
}
for(register int i=1;i<=n;i++){
if(!v[i]){
int p=b+(1<<(i-1));
if(dp[p][i]!=0&&dp[p][i]<=s+dis(now,i)) continue;
v[i]=1;
dp[p][i]=s+dis(now,i);
dfs(t+1,i,dp[p][i],p);
v[i]=0;
}
}
}
int main(){
scanf("%d",&n);
for(register int i=1;i<=n;i++)
scanf("%lf%lf",&a[i],&b[i]);
dfs(0,0,0,0);
printf("%.2lf\n",ans);
return 0;
}