题目描述
房间里放着 n块奶酪。一只小老鼠要把它们都吃掉,问至少要跑多少距离?老鼠一开始在 (0,0) 点处。
输入格式
第一行有一个整数,表示奶酪的数量 n。
第 2 到第 (n + 1) 行,每行两个实数,第 (i + 1)行的实数分别表示第 i 块奶酪的横纵坐标xi,yi。
输出格式
输出一行一个实数,表示要跑的最少距离,保留 2 位小数。
输入输出样例
输入
4
1 1
1 -1
-1 1
-1 -1
输出
7.41
说明/提示
数据规模与约定
对于全部的测试点,保证 1≤n≤15,∣xi∣,∣yi∣≤200,小数点后最多有 3 位数字。
提示
对于两个点 (x1,y1),(x2, y2)(x2,y2),两点之间的距离公式为
完整代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=30;
int m;
double ans=1e9;//记录最短路径长度
int show[maxn];//记录该奶酪是否已经吃过
double lens[maxn][maxn];//lens[i][j]记录第i个点到第j的点的距离
double a[maxn][2];//记录奶酪的坐标
double dp[1<<15][maxn];//状态压缩,第一个下标代表已经吃到的奶酪,1代表已经吃到,0代表没有吃到
//第二个下标代表当前奶酪的位置
void dfs(int n,int state,int number,double sum)
{//eg:state=10010,代表吃了第二个和第五个奶酪(从右往左)
if(number==m+1)
{
ans=min(sum,ans);
return ;
}
for(int g=1;g<=m;g++)
{
if(!show[g])//如果没有出现过
{
int nowstate=state+(1<<(g-1));
if(dp[nowstate][g])//如果之前状态有值
{
if(dp[nowstate][g]<=sum+lens[n][g])//之前状态的值小于现在状态则不再需要处理了,相当于剪枝
continue;
}
show[g]=1;
dp[nowstate][g]=sum+lens[n][g];//更新当前状态的值
dfs(g,nowstate,number+1,dp[nowstate][g]);
show[g]=0;
}
}
return;
}
int main()
{
scanf("%d",&m);
a[0][0]=0;
a[0][1]=0;//原点的坐标
for(int i=1;i<=m;i++)
{
scanf("%lf %lf",&a[i][0],&a[i][1]);
}
//计算第i个点到达第j个点的长度
for(int i=0;i<=m;i++)
{
for(int j=i+1;j<=m;j++)
{
double lenx=a[i][0]-a[j][0];
double leny=a[i][1]-a[j][1];
lens[i][j]=sqrt(lenx*lenx+leny*leny);
lens[j][i]=lens[i][j];
}
}
dfs(0,0,1,0);//第一个参数表示当前走的是第几个奶酪,第二个参数代表当前状态压缩表示吃到的奶酪的状态
//第三个参数-1代表当前吃到的奶酪个数,第四个参数代表当前距离的值
printf("%.2f",ans);
return 0;
}