HDU - 1584 DFS剪枝

版权声明:博主的博客不值钱随便转载但要注明出处 https://blog.csdn.net/easylovecsdn/article/details/82779272

这道题让我先是超时再是WA,真是无语,hdu的讨论里说dp也能做(好久没碰dp了),既然是练搜索嘛,那就用搜索做,dfs玩的就是回溯,这句话是在一个博客里看的,现在感觉颇有道理。

本题需要对dfs剪枝,虽然我的代码在没有剪枝的情况下也过了(我觉得是数据水了),大家可以看以下的提交记录;

这是未剪枝的情况:

这是剪枝的情况:

大家可以看到仅仅一句代码(见dfs函数里的剪枝代码——已注释),时间从904ms缩减到140ms,在此我为大家解释下剪枝代码的含义,if (times >= ans) return ; dfs函数中的times参数记录的是移动的总距离,我们追求的答案是移动的最小距离,如果你此时找的times比你已经找到的最终答案ans'还要大,那么你将没有必要继续进行搜索,这将省去很多无用的判断,当然还可能有更多的剪枝方法,我这里列举的只是其一,欢迎大家在评论里指出。

在这里我在给大家一组测试数据,如下代码注释中的数据,正确答案为11。

#include <bits/stdc++.h>
#define min(x, y)   x < y ? x : y
#define INF 0x3f3f3f3f
using namespace std;

int a[11];
int ans;
bool vis[11];

/*
1
3 4 1 2 5 6 7 8 9 10
*/

int findNext(int inx)  //寻找下标为inx的元素应该移动到的正确位置
{
    for (int i = 1; i < 11; i++) {
        if (a[i] == a[inx] + 1) {
            if (vis[i] == false) return i;
            else return findNext(i);
        }
    }
}

int Move(int inx)   //计算移动的距离
{
    return abs(inx-findNext(inx));
}


void dfs(int times, int num)
{
    if (times >= ans) return ;   //dfs剪枝

    if(num == 9) {
        ans = min(ans, times);
        return ;
    }


    for (int i = 1; i < 11; i++) {

        if (a[i] == 10) continue;

        if (vis[i] == false) {
            vis[i] = true;
            dfs(times+Move(i), num+1);
            vis[i] = false;
        }
    }
}


int main()
{
    int t;
    cin >> t;
    while (t--) {
        for (int i = 1; i < 11; i++) cin >> a[i];
        memset(vis, false, sizeof(vis));
        ans = INF;
        for (int i = 1; i < 11; i++) {
            if (a[i] == 10) continue;
            vis[i] = true;
            dfs(Move(i), 1);
            vis[i] = false;
        }
        cout << ans <<endl;
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/easylovecsdn/article/details/82779272