刚接触回溯,最基础的回溯,做了近两小时,终于调出来了 (介于初学,代码质量不高,仅供参考,大神走开。。)。
回溯要注意的是:
递归的入口和出口, 进入的时候的形参和出来的答案是否遍历所有该遍历的,或者说完成了一次深搜(也就是完成了一次所有该选的数据, 比如八皇后的一次枚举就是选齐八个皇后,本题则是连接了所有的点),当然在所有遍历完后是否得到了正确答案,比如这题,是否得到了最小距离。
还有就是,如果设了状态变量(一般都是要设的,比如枚举的时候,用来表示是否之前遍历过,也就是说本次能不能选这个点的一个标记,通常是一组数组,本题如下面代码的picked),一定要在一个递归函数的出口把之前变过的再变回来。 具体的说: 如果在递归本次的时候,此前已经连接了这个点,就应该设为true,之后判断,如果是true则不能再选这个点了,就继续遍历还有什么点能选。如果这次的n个点已经找到了,必然要return ,也就是一次递归的出口,那此时就应该把已经标记为true的点改回到false.
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define INF 2000000000
using namespace std;
int n;
int sequence[10], ans[10];
double minDis, curDis;
bool picked[10];
struct Node {
double x, y;
} node[10];
void dfs(int cur, double curDis)
{
if(curDis >= minDis) { return ; }
if(cur == n - 1) {
curDis += sqrt( (node[sequence[cur]].x - node[sequence[cur - 1]].x) * (node[sequence[cur]].x - node[sequence[cur - 1]].x) +
(node[sequence[cur]].y - node[sequence[cur - 1]].y) * (node[sequence[cur]].y - node[sequence[cur - 1]].y) );
if(curDis < minDis) {
minDis = curDis;
for(int i = 0; i < n; i ++) {
ans[i] = sequence[i];
}
}
return ;
}
if(cur) {
curDis += sqrt( (node[sequence[cur]].x - node[sequence[cur - 1]].x) * (node[sequence[cur]].x - node[sequence[cur - 1]].x) +
(node[sequence[cur]].y - node[sequence[cur - 1]].y) * (node[sequence[cur]].y - node[sequence[cur - 1]].y) );
}
int k;
for(k = 0; k < n; k ++) {
if(!picked[k]) {
picked[k] = true;
sequence[cur + 1] = k;
dfs(cur + 1, curDis);
picked[k] = false;
}
}
}
int main()
{
int curCase = 1;
while(scanf("%d", &n), n) {
memset(picked, false, sizeof(picked));
picked[0] = true;
int i;
for(i = 0; i < n; i ++)
scanf("%lf%lf", &node[i].x, &node[i].y);
minDis = INF;
for(i = 0; i < n; i ++) {
//memset(picked, false, sizeof(picked));
sequence[0] = i;
picked[i] = true;
dfs(0, 0);
picked[i] = false;
}
printf("**********************************************************\n");
printf("Network #%d\n", curCase ++);
for(i = 0; i < n - 1; i ++) {
printf("Cable requirement to connect (%.0lf,%.0lf) to (%.0lf,%.0lf) is %.2lf feet.\n",
node[ans[i]].x, node[ans[i]].y,
node[ans[i + 1]].x, node[ans[i + 1]].y,
16 + sqrt( (node[ans[i]].x - node[ans[i + 1]].x) * (node[ans[i]].x - node[ans[i + 1]].x) +
(node[ans[i]].y - node[ans[i + 1]].y) * (node[ans[i]].y - node[ans[i + 1]].y)
));
}
printf("Number of feet of cable required is %.2lf.\n", minDis + 16 * (n - 1));
}
return 0;
}