dfs剪枝(排除等效冗余)

一、剪枝优化

1.优化搜索顺序:有限考虑分支较少的搜索方式,常见的比如从大到小排序
2.排除等效冗余:排除等效的情况,本题就是很好的例子,稍后解释
3.可行性剪枝
4.最优性剪枝

二、本题的排除等效冗余

1.如果是木棒的第一段就搜索失败了,则一定搜不到方案
2.如果是木棒的最后一段搜索失败了,则一定搜索不到方案
3.如果木棒的长度为k的一段搜索失败了,那么后续同样长为k的一段同样也会搜索失败

剪枝3 比较明显,下面证明剪枝1剪枝2

例如:\(1,1,1,3,.....\)

对于剪枝1,我们用反证法:假设某个木棒的第一段搜索失败了,存在解决方案
假如开始将 \(3\) 作为木棒 \(a\) 的第一段搜索失败了,但存在一种合法方案,那么 \(3\) 肯定会放在后面的木棒 \(b\) 中,但我们交换木棒 \(a\) 和木棒 \(b\) 的搜索顺序并不会影响答案,因此这与 \(3\) 作为木棒 \(a\) 的第一段搜索失败矛盾。

对于剪枝2,我们用反证法:假设某个木棒的最后一段搜索失败了,存在解决方案
假如将 \(3\) 作为木棒 \(a\) 的最后一段搜索失败了,但存在一种合法方案,那么肯定会存在 \(k(k>1)\) 根木棒(不妨为 \(1,1,1\) )使得这 \(k\) 根木棒作为 \(a\) 的最后阶段成功,并且 \(3\) 作为木棒 \(b\) 的一段成功,同理我们可以将 \(3\) 看作木棒 \(b\) 的最后一段,而交换木棒 \(a\) 和木棒 \(b\) 的搜索顺序并不会影响答案,故矛盾。

参考----------->

三、Code

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 70;

int n, w[N];
bool st[N]; // 因为我们需要剪枝实现跳跃,因此需要st标记

// 当前已经恢复了cnt根木棍,每根木棍的长为length
// 当前正在恢复的木棍长为cur
// 下次dfs从start开始遍历w数组
// 所有木棍长度之和为sum
int sum, length;
bool dfs(int cnt, int cur, int start)
{
    if(cnt * length == sum) return true;
    if(cur == length)   return dfs(cnt + 1, 0, 0);
    
    for(int i = start; i < n; i ++ )
    {
        if(!st[i] && cur + w[i] <= length)
        {
            st[i] = true;
            if(dfs(cnt, cur + w[i], i + 1)) return true;
            st[i] = false;
            
            // 走到这里说明第i根木棍放在这没有合法方案
            
        // case1
            if(!cur)    return false;       
        // case2
            if(cur + w[i] == length)    return false; 
        // case3,下一次for从j开始,但下一次dfs仍从start开始
            int j = i;
            while(j < n && w[j] == w[i])    j ++ ;
            i = j - 1;
        }
    }
    return false;
}

int main()
{
    while(cin >> n, n)
    {
        memset(st, false, sizeof st);
        sum = 0;
        for(int i = 0; i < n; i ++ )    cin >> w[i], sum += w[i];
        sort(w, w + n, greater<int>()); // 从大到小排序,优化搜索顺序
        for(length = 1; length <= sum; length ++ )
        {
            if(sum % length == 0 && sum / length <= n && dfs(0, 0, 0))
            {
                cout << length << endl;
                break;
            }
        }
    }
    return 0;
}
posted @ 2024-03-03 10:12  光風霽月  阅读(39)  评论(0编辑  收藏  举报