[算进] 小木棍

Problem

ACwing 题目地址

洛谷 题目地址

Before

做完16*16的数独后感觉这些搜索题都是小清新。

但是小木棍这题还是烦了我特别久,因此来写篇题解吧,总结一下。

Sulotion

这题无非就是两个剪枝,优化搜索顺序 + 去掉等效状态

优化搜索顺序

  • 1.很明显,从大到小排,这样未来可选择的空间更少,搜索树更小。

去掉等效状态

  • 1.假设一条木棍是由 1,3,6 拼接成的,1,6,3 和 3,1,6 这些顺序就是等效状态。我们只要保证每根大木棍内部编号顺序递增,那么就可以剪掉这些等效状态。

  • 2.假设用长度为 5 的木棍拼接失败,那么就要跳过所以长度为 5 的木棍。所以跳过长度相等的并且失败了的木棍

  • 3.如果第一个木棍拼接失败,那么可以剪掉这个分支。反证法:条件:第一个木棍拼接失败。假设这个这个分支可以成功,那么将第一根木棍所在的那条大木棍放在第一个木棍这里,就可以拼接成功,条件不成立,故原命题成立。如果最后一个木棍拼接失败,那么可以剪掉这个分支,因为最后一个木棍是恰好可以拼好这个大木棍的,它的位置必须在这里,如果不行的话就说明这里不能成功拼接。

Code

Talk is cheap.Show me the code.

#include<bits/stdc++.h>
using namespace std;
inline int read() {
    int x=0,f=1; char ch=getchar();
    while(ch<'0' || ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { x=(x<<3)+(x<<1)+(ch^48); ch=getchar(); }
    return x * f;
}
const int N = 107;
int n,sum,len,ans;
int sticks[N];
bool vis[N];
bool cmp(int x,int y) {
    return x > y;
}
bool Dfs(int tot,int now,int start) {   //保证每根木棍内元素递增 
    if(tot*len == sum) return true;
    if(now == len) return Dfs(tot+1,0,0);
    for(int i=start;i<=n;++i) {
        if(vis[i]) continue;
        if(now+sticks[i] <= len) {
            vis[i] = 1;
            if(Dfs(tot,now+sticks[i],i+1)) return true;
            vis[i] = 0;
            if(!now) return false;  //这是第一个木棍,
            if(now+sticks[i] == len) return false; //这是最后一根木棍
            int j = i;
            while(j<=n && sticks[j]==sticks[i]) ++j;
            i = j - 1;  //跳过相同木棍 
        }
    }
    return false;
}
void work() {
    memset(vis, 0, sizeof(vis)); sum = 0; ans = -1;
    for(int i=1;i<=n;++i) {
        sticks[i] = read();
        sum += sticks[i];
    }
    sort(sticks+1, sticks+1+n, cmp);
    for(int i=1;i<=sum;++i) {
        if(sum%i == 0) {
            len = i;
            if(Dfs(0,0,0)) {
                ans = i; break;
            }
        }
    }
    printf("%d\n",ans);
}
int main()
{
    while(true) {
        n = read();
        if(n == 0) break;
        work();
    }
    return 0;
}

Summary

  • 看到搜索题第一步想优化枚举顺序

  • 第二步剪去等效状态

    扫描二维码关注公众号,回复: 8416990 查看本文章

猜你喜欢

转载自www.cnblogs.com/BaseAI/p/12148955.html
今日推荐