【DFS&&搜索剪枝】CODE[VS] 3498 小木棍

本文通过一道编程题探讨暴力枚举算法的优化方法,包括木棍长度排序、目标长度范围限定等技巧,有效减少搜索时间。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

点击进入地狱


这个搜索做得比较早了….
11.1下午来机房开始搞这个暴搜,结果一直TLE&&WA

这里写图片描述

后来放了会没再管,11.3号早上又想了起来
然后就开始了悲惨的WA之路QAQ:

这里写图片描述


这里写图片描述


题是好题,是我太弱了…..


这道题的思路:
暴力枚举
我们枚举目标长度,当目标长度可以整除给出木棍长度之和的时候,我们再去判断这些木棍是否可以拼成该长度,这比枚举木棍根数要快并且更容易想到优化
(别问我怎么知道的,说多了都是泪)

但是裸暴力会超时,所以需要剪枝优化


1.首先很显然的一个剪枝,就是贪心,先将木棍从长到短排序,然后拼的时候先枚举长木棍的组合,因为长木棍限制更高,能够很快排除不少情况
2.然后我们可以在枚举目标木棍长度的时候,从给出木棍最长的开始到所有长度总和结束,因为显然目标木棍长度必然大于或等于数据给出的最长木棍长度
3.如果当前长度为0(第一层搜索),完成之后直接返回
4.在拼接木棍的的时候,相同长度的木棍之前用过,记录一下,下次直接continue
5…………………………………………………………………………………………..


代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <queue>

using namespace std;

int n,u;
int osu; 
int len[105];
int totlen;
int ans = 0x3ffffff;
bool used[105];

inline int read()
{
    char ch;
    int f = 1;
    int data = 0;
    while(ch < '0'||ch > '9')
    {
        ch = getchar();
        if(ch == '-')
            f = -1;
    }
    do{
        data = data*10+ch-'0';
        ch = getchar();
    }while(ch <= '9'&&ch >= '0');

return f*data;
}

bool cmp(const int a,const int b) { return a > b;}

inline bool dfs(int s,int nowlen,int viv)
{   
    bool bj;
    if(nowlen == 0) bj = true;
    else bj = false;
    if(s == u) return true;
    for(int i = viv;i <= n;i++)
    {
        if(used[i] == 1) continue;
        if(nowlen + len[i] == osu)
        {
            used[i] = 1;
            if(dfs(s+1,0,0)) return true;
            used[i] = 0;
            return false;
        }
        else if(nowlen + len[i] < osu)
        {
            used[i] = 1;
            if(dfs(s,nowlen+len[i],i)) return true;
            used[i] = 0;
            if(bj == true) return false;
        }
    }
return false;
}

int main()
{
    n = read();
    for(int i = 1;i <= n;i++)
    {
        len[i] = read();    
        totlen += len[i];
    }
    sort(len+1,len+1+n,cmp);
    for(int i = len[1];i <= totlen;i++)
    {
        if(totlen%i == 0)
        {       
            osu = i;
            u = totlen/i;
            memset(used,0,sizeof(used));
            if(dfs(1,0,0)) { ans = min(ans,i); continue;}
        }
    }
    printf("%d\n",min(ans,totlen));

return 0;
}

THE END

By Peacefuldoge

http://blog.youkuaiyun.com/loi_peacefuldog

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值