洛谷P1120 小木棍 - 搜索

10 篇文章 0 订阅

想了想不知道原来棍子长度为多少的情况下,很难去搜索和确认最终状态,不确定的时候就枚举,遇事不决就枚举,反正是写暴力算法,为什么不多枚举呢
枚举了原来棍子长度时,可以顺便确定有多少根棍子,因为这个长度必须是所有棍子现在长度之和的约数
然后要加许多剪枝。。。

1.减小搜索树规模,从能够展开分支较少的情况开始搜索(把木棍从大到小排列)
2.若挑选了长度为x的棍子去拼目前的原棍子,结果这一分支失败了,那么记录下这个长度,以后遇到相同长度的棍子不要拼了
3.若一根原棍子拼的第一根小木棍x就失败了,那么直接返回失败,这一分支可以不考虑了,因为你总是需要x这一根棍子,如果这根原棍子上面不能有x棍子,那么其他还没开始拼的原棍子同样也不能有x棍子(因为条件是x作为这根原棍子的第一根拼接棍,那么这根原棍子就是“空”的,那么这跟原棍子和其他“空棍子”是等效的,失败的等效的搜索不应该执行多次),最后棍子用不完。
4.如果在目前状态,加上一根棍子就拼好了一个原棍子,那么不需要搜索在目前状态加上其他小棍子拼好原棍子的情况,就是说如果加上一根棍子就能拼成一根原棍子了,那目前状态下其他的分支就可以不搜索了,直接跳过后面的搜索,因为求的不是方案数,而是判断是否有解,所以如果一根和几根效果是一样的,那么只要搜索一根就可以了

使用void型搜索记得每次搜之前把flg = false

使用bool型搜索记得dfs函数最下面返回一个false(有返回值总不能不返回对吧,而且如果执行完循环还没返回说明搜索失败)

针对bool型在最后一行忘敲return false…我先写函数参数表,再写返回什么东西 再写函数内部的东西,这样就不会丢掉什么
这是一种习惯,先写好具体大纲框架,再写具体函数操作,就是先写好下面的东西,再写省略号里面的东西

bool dfs(int x) {
    (...)
    return false;
}
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
#define debug(x) cerr << #x << "=" << x << endl;
const int MAXN = 100000 + 10;
int n,nn,stk[MAXN],ans=1<<30,a[MAXN],sum,tempp,len,cnt,vis[MAXN],maxx;
bool cmp(int a, int b) {
    return a > b;
}
bool dfs(int stick, int cab, int last) {
    if(stick == cnt + 1) return true;
    if(cab == len) return dfs(stick+1, 0, 1);
    int fail = 0;
    for(int i=last; i<=n; i++) {
        if(!vis[i] && cab+a[i] <= len && a[i] != fail) {
            vis[i] = 1;
            if(dfs(stick, cab+a[i], i+1)) return true;
            fail = a[i];
            vis[i] = 0;
            if(cab == 0 || cab+a[i] == len) return false;
        }
    }
    return false;
}
int main() {
    scanf("%d", &nn);
    for(int i=1; i<=nn; i++) {
        int tempp;
        scanf("%d", &tempp);
        if(tempp <= 50) a[++n] = tempp, sum += tempp,maxx = max(maxx, a[n]);
    } 
    sort(a+1,a+n+1,cmp);
    for(len=maxx; len<=sum; len++) {
        if(sum % len == 0) {
            cnt = sum / len;
            memset(vis,0,sizeof(vis));
            if(dfs(1, 0, 1)) break;
        }
    }
    printf("%d", len);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值