点击查看代码
#include <bits/stdc++.h>
using namespace std;
int n;
double x[20], y[20];//记录多组坐标
double w[20][20]; // 【优化1】预处理距离矩阵
double ans = 1e9;
bool vis[20];//检查是否访问过
// 计算两点距离
double dist_func(int i, int j) {
return sqrt((x[i]-x[j])*(x[i]-x[j]) + (y[i]-y[j])*(y[i]-y[j]));
}
//1.状态定义,当前点,当前经过点的数量,走的总距离
void dfs(int now, int count, double sum_dist) {
// 2.剪枝,最优性剪枝(底线是贪心)
if (sum_dist >= ans) return;
//3.截止条件,访问过n个点
if (count == n) {
ans = min(ans, sum_dist);
return;
}
//4.枚举选择,访问没走过的点
for (int i = 1; i <= n; i++) {
if (!vis[i]) {
vis[i] = true;
// 直接查表 w[now][i],不用重复算 sqrt
dfs(i, count + 1, sum_dist + w[now][i]);
//5.回溯
vis[i] = false;
}
}
}
int main() {
//读入数据,每一组坐标存在一个索引指向的x,y数组中
cin >> n;
x[0] = 0; y[0] = 0;
for (int i = 1; i <= n; i++) cin >> x[i] >> y[i];
// 优化1预处理两两点之间的距离,这样在dfs时就不用调用sqrt函数了,而是直接查表就可以了,避免了很多重复计算
for(int i=0; i<=n; i++){
for(int j=0; j<=n; j++){
w[i][j] = dist_func(i, j);
}
}
//优化2,贪心搜索,先找到一个看上去不错的解
double greedy_sum = 0;
int cur = 0;
bool g_vis[20] = {0};
for(int step=1; step<=n; step++){
int next_best = -1;
double min_d = 1e9;
// 每次找离当前点最近的未访问点
for(int i=1; i<=n; i++){
if(!g_vis[i] && w[cur][i] < min_d){
min_d = w[cur][i];
next_best = i;
}
}
g_vis[next_best] = 1;
greedy_sum += min_d;
cur = next_best;
}
//把贪心结果作为最优性剪枝的底线,这样可以避免初期很多无效的搜索
ans = greedy_sum;
// 开始真正的搜索
dfs(0, 0, 0.0);
printf("%.2f\n", ans);
return 0;
}