输入输出样例
输入 #1复制
4
1 1
1 -1
-1 1
-1 -1
输出 #1复制
7.41
总结目录
1 本题搜索思路
2 本题剪枝思路
1 本题搜索思路
这题搜索就是典型的dfs搜索,并且使用回溯记录哪些点是访问过的。在求距离的时候需要知道当前在第几个点,这样才能继续往下求距离。当全部点访问完之后,就“走到尽头”了,此时比较一下当前的sum和minres的大小就可以知道哪个是最小值了。minres初始化为一个很大的数,这里使用了int_max
2 求最大最小值的dfs剪枝思路
以上的算法显然暴力dfs会TLE,因此要考虑加速的方法。加速的话一个是记忆化搜索。一个是使用剪枝。记忆化搜索的话最好是用在结果不会更新的情况,即算出来之后,后面的计算都是可以用这个结果的。这样会比较好,但是这题里面好像不太合适。 其实这里也可以用一点点,就是去记忆化两条边之间的距离,这样就不用dist2p函数来计算了,但是这样其实加速得不多。
这题实际上用剪枝其实更明显。因为要求最大最小值,所以在计算过程中一定是不断地递增的。所以我们只需要在num<n的时候加一个判断,看sum和当前的minres进行比较,如果更小的话才进行后续搜索;如果还没有到底已经超过了minres那么也就没有必要进行后续的搜索了。这个剪枝方法在求最大最小值的题目中被常常用到。
代码
#include<iostream>
#include<cmath>
#include<algorithm>
#include<climits>
using namespace std;
#define maxsize 20
int used[maxsize];//记录访问过的点数
double minres = INT_MAX;
int n;
struct Point {
double x;
double y;
};
Point points[maxsize];
double dist2p(Point a, Point b) {
//计算两点之间距离
return sqrt((a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y));
}
void dfs(int num,int curpos,double sum) {
//num表示已经访问过的点的数量
if (num<n&&sum>=minres) {
return;//剪枝
}
if (num >= n) {
minres = min(sum, minres);
return;
}
for (int i = 1; i <= n; i++) {
if (used[i] != 1) {
used[i] = 1;
double dst = dist2p(points[curpos], points[i]);
dfs(num + 1, i, sum + dst);
used[i] = 0;
}
}
}
int main() {
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> points[i].x >> points[i].y;
}
points[0].x = 0;
points[0].y = 0;
dfs(0,0,0);
printf("%.2f", minres);
return 0;
}