题目描述
房间里放着 𝑛n 块奶酪。一只小老鼠要把它们都吃掉,问至少要跑多少距离?老鼠一开始在 (0,0)(0,0) 点处。
输入格式
第一行有一个整数,表示奶酪的数量 𝑛n。
第 22 到第 (𝑛+1)(n+1) 行,每行两个实数,第 (𝑖+1)(i+1) 行的实数分别表示第 𝑖i 块奶酪的横纵坐标 𝑥𝑖,𝑦𝑖xi,yi。
输出格式
输出一行一个实数,表示要跑的最少距离,保留 22 位小数。
输入输出样例
输入 #1复制
4 1 1 1 -1 -1 1 -1 -1
输出 #1复制
7.41
说明/提示
数据规模与约定
对于全部的测试点,保证 1≤𝑛≤151≤n≤15,∣𝑥𝑖∣,∣𝑦𝑖∣≤200∣xi∣,∣yi∣≤200,小数点后最多有 33 位数字。
提示
对于两个点 (𝑥1,𝑦1)(x1,y1),(𝑥2,𝑦2)(x2,y2),两点之间的距离公式为 (𝑥1−𝑥2)2+(𝑦1−𝑦2)2(x1−x2)2+(y1−y2)2。
#include<iostream>
#include<stdio.h>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int n;
double d[20][20], dp[(1 << 15) + 15][20], zb[20][2];
//d数组存储任意两点的最短距离
// dp[j]意思用2进制来存储点信息,第几位为1代表该点已经走过
// dp[j][i]第2个位置代表当前状态以i点为末位的值
// 每种状态代表每种状态的最短距离
//zb代表着存储坐标的意思,[0]是x轴坐标,[1]是y轴坐标
double res = 1e9, dx, dy;
bool vis[20];
//ge代表已经跑的点的个数,now代表现在在哪个点
//nums代表当前走过的距离和,zt代表每一种状态
void dfs(int ge, int now, double nums, int zt)
{
if (ge == n) //所有点走完后,看结果是否值得保留
{
if (nums < res)
res = nums;
return;
}
for (int i = 1;i <= n;i++)
{
if (vis[i] == 0)
{
int zt2 = zt + (1 << (i - 1));
double dis = nums + d[now][i];
if (dp[zt2][i] != 0)
{
if (dis >= dp[zt2][i])
continue;
}
//优化每个状态的最小值
vis[i] = 1;
dp[zt2][i] = dis;
dfs(ge + 1, i, dis, zt2);
vis[i] = 0;
}
}
}
int main()
{
cin >> n;
d[0][0] = 0;d[0][1] = 0; //初始化
for (int i = 1;i <= n;i++) //输入数据计算每两点之间的距离
{
cin >> zb[i][0] >> zb[i][1];
for (int j = 0;j < i;j++)
{
dx = zb[i][0] - zb[j][0];
dy = zb[i][1] - zb[j][1];
d[i][j] = sqrt(dx * dx + dy * dy);
d[j][i] = d[i][j];
}
}
//从0到每个点开始深度优先查找,直到每个点都跑一遍
for (int i = 1;i <= n;i++)
{
vis[i] = 1;
dfs(1, i, d[0][i], 1 << (i - 1));
vis[i] = 0;
}
printf("%.2lf", res);
}