UVa 216 - Getting in Line 回溯,简单递归枚举

刚接触回溯,最基础的回溯,做了近两小时,终于调出来了 (介于初学,代码质量不高,仅供参考,大神走开。。)。

回溯要注意的是:

       递归的入口和出口, 进入的时候的形参和出来的答案是否遍历所有该遍历的,或者说完成了一次深搜(也就是完成了一次所有该选的数据, 比如八皇后的一次枚举就是选齐八个皇后,本题则是连接了所有的点),当然在所有遍历完后是否得到了正确答案,比如这题,是否得到了最小距离。

       还有就是,如果设了状态变量(一般都是要设的,比如枚举的时候,用来表示是否之前遍历过,也就是说本次能不能选这个点的一个标记,通常是一组数组,本题如下面代码的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;
}


 

       

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值