【破烂集】 排列dfs的一个小发现

优化得还不是太好

突然发现一个不错的好方法,可以优化排列组合dfs中的一些困难(比如输出排列),并且在时间上也有所优化,故而一提。

对于组合数的问题的确一直是一个难题,而且我做的的确也不好,记得之前在做第三周的E的时候就是因为要输出排列,而我的那个方法简直坑到了极点,所以勉强过关,在发现了这个方法之后,我突然眼前一亮,感觉有了一雪前耻的机会。

先说说我一般对组合数搜索处理的思路,第一种是最暴力的,直接用next_permutation一个一个找,这个函数是挺高级的,但是这个方法就太烂了,因为毫无剪枝,所以复杂度必然极高,不适合做题使用。第二个方法是我常用的方法,是挑战里面的,用一个used函数保存使用过的元素,这样每次查找都是一个N的复杂度,但是因为有剪枝,所以要快很多,但是这样的坏处就是不能保存路径。当然有了新方法之后这两种方法可以直接扔掉了。

介绍一下这个新方法(可能有些人就是这种方法)
直接用swap来处理组合数,非常的快,极限复杂度也只有阶乘,而且还能剪枝,还可以直接输出路径,可谓是强得一b。就用1085这道题来示范一下吧。

# include <cstdio>

const int MAX_N = 10;

int ans;
int A[MAX_N];
int N, K;

inline int abs(int a)
{
    return a < 0 ? -a : a;
}

inline void swap(int &a , int &b)
{
    if(a - b)
        a ^= b ^= a ^= b;
}

void dfs(int x)
{
    if(x == N)
    {
        if(abs(A[0] - A[x - 1]) <= K)   
            ans++;

        return;
    }

    int i;
    for(i = x ; i < N ; i++)
    {
        swap(A[i] , A[x]);
        if(abs(A[x - 1] - A[x]) <= K)
            dfs(x + 1);
        swap(A[i] , A[x]);
    }
}

int main()
{
    while(~scanf("%d %d", &N, &K))
    {
        int i;
        for(i = 0 ; i < N ; i++)
            scanf("%d", &A[i]);

        ans = 0;
        dfs(1);
        printf("%d\n", ans);
    }

    return 0;
}

先说一个注意事项,就是这个swap,这个方法的确很巧妙,但是有一个致命的bug,就是如果是两个相同的变量(注意是相同,不是相等)做的话这个变量会变成0,所以最好要加上判断。

因为每次都用一个swap来改变数组的排列,所以我们当前的A必然是这个排列拍好一部分的状态,如果要输出的话,直接输出A即可。

再测试一下
E题的优化

突然发现这个方法暂时并不适用于输出排列,因为它输出的不是按照字典序进行的,所以的确是有一些问题,还得研究研究。

先做个总结吧,这个方法暂时没有什么特别大的使用空间,因为它只能在不输出排列的情况下暂时提高一些速度,至于是否可以达到字典序,我还得好好研究研究。

猜你喜欢

转载自blog.csdn.net/qq_40772738/article/details/80461137