sicily1142(深搜加剪枝)

数据结构期末考试最后一道题,到现在才写出来哈。。
还是因为看了《编程之美》这本书一摞烙饼的排序问题之后才写的。
看完编程之美,才发现这道题原来这么坑。没有在多项式复杂度的解法。
然后我首先用编程之美类似的方法,导致time limit
《编程之美》书中的方法是先给定的upperbound为2*countn-1
当dfs之后有比upperbound小的再动态修改upperbound,
这样的方法,
对于数列长度小的
剪枝并不太明显,有可能需要全部穷举之后才有。
所以我就网上搜了下资料
http://blog.csdn.net/fanfank/article/details/8976905
他的解法给我很大的启发,
在数列长度小的数组
下界值(当前序列排序最少需要的次数)
循环1~n通过判断相邻数列是否为数列排序后也相邻,不相邻则sum++,得到下界值sum
这样每次dfs到达与下界值同样的深度或者通过预判(下界值+当前深度)超过下界值,就停止继续搜索进行剪枝,达到更快的效率
这道题跟编程之美的不同之处还在于其序列不是1~n而是n个绝对值不超过32767
所以下界值不是简单判断相邻数的差小于1或者-1而是判断排序后的索引是否相邻

#include <cstdio>
#include <algorithm>
using namespace std;
struct SortArray {
    int index;
    int x;
    friend bool operator< (const SortArray& a, const SortArray& b) {
        return a.x < b.x;
    }
}s[30], Array[30];
int max_swap;
int n;
//判断相邻值排序后是否相邻
int lowerbound(int n) {
    int sum = 0;
    for (int i = 1; i < n; i++) {
        if (Array[i].index - Array[i-1].index == 1 || Array[i].index - Array[i-1].index == -1)
            ;
        else
            sum++;
    }
    return sum;
}
bool check(int n) {
    for (int i = 1; i < n; i++) {
        if (Array[i].x < Array[i-1].x)
            return false;
    }
    return true;
}
void reverse(int end) {
    for (int i = 0; i <= end/2; i++)
        swap(Array[i], Array[end-i]);
}
bool dfs(int step) {
    if (lowerbound(n) > step)//进行预判,判断下界是否大于step,
        return false;
    if (check(n))
        return true;
    for (int i = 1; i < n; i++) {//穷举可能的翻转
        reverse(i);
        if (dfs(step-1))
            return true;
        reverse(i);
    }
    return false;
}
int main() {
    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        scanf("%d", &Array[i].x);
        s[i].x = Array[i].x;
        s[i].index = i;//记录该序列原始的索引
    }
    sort(s, s+n);//对s进行排序
    for (int i = 0; i < n; i++) {
        Array[s[i].index].index = i;//通过s记录的索引,找回原来数组的值,并给其添加排序后的索引,方便判断相邻值排序后是否相邻
    }
    int step = lowerbound(n);//下界,最少需要翻转的次数
    while (!dfs(step++));
    printf("%d\n", step-1);
    return 0;
}

你可能感兴趣的:(编程之美,DFS,sicily)