洛谷 P1120 & WUSTOJ 2575 小木棍 【DFS+剪枝】

题目来源:洛谷:https://www.luogu.org/problemnew/show/P1120
WUSTOJ http://acm.wust.edu.cn/problem.php?id=2575&soj=0
在这里插入图片描述
★想想就气【其实还是自己太菜】 居然被书坑了,但是自己没有一点主观意识,请教了学长才发现 书上的代码是有问题的 !不能通过所有样例~
★EMMM,实在是不好意思,等我回来再做这题的时候 发现我的代码贴错了~在此说声对不起,该题题解已更新 请放心食用 awa

思路:

采用深搜,但是直接搜肯定是会超时的,必须要巧妙的剪枝~
剪枝一: 短的木棍拼凑更加的灵活,所以我们不妨将木棍按 从长到短排序 方便搜索
剪枝二: 解最小是 最长的木棍的长度 ,而最大是 只剩下一根木棍的时候 即所有木棍的和
剪枝三: 在循环时 只有能被 所有木棍长度和 整除的长度 才可能是答案
剪枝四: 已经找到答案就不用再搜索了
剪枝五: 如果这时last=0 就说明新的搜索刚刚开始 搜谁都行 ,如果刚刚匹配成功 那就是 最好的匹配,不需要再搜索~
剪枝六: 如果下一个f[ i ] 和这一个相等,那不就是重复搜一样的结果嘛,剪枝~

代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn=100;
const int mod=1e9+7;
typedef long long LL;
bool vis[maxn];
int f[maxn];
int n,m;
bool flag;
inline void read(int &x)
{
    char c; x=1;
    while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
    int res=c-'0';
    while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
    x*=res;
}
bool cmp(int a,int b) {return a>b;}                     //从大到小排序
void hhh(int last,int num,int pos,int len)
{
    if(num==n&&last==len) {flag=1; return ;}           
    if(last==len){
        last=0;
        pos=1;
    }
    for(int i=pos;i<=n;i++){
        if(vis[i]) continue;                          //选过的直接跳过
        if(last+f[i]<=len){
            vis[i]=1;
            hhh(last+f[i],num+1,i+1,len);
            if(flag) return ;                        //剪枝4
            vis[i]=0;                                //回溯
            if(last+f[i]==len||last==0) break;       //剪枝5
        }
        while(f[i]==f[i+1]) i++;                     //剪枝6
    }
}
int main()
{
    while(~scanf("%d",&n)&&n){
        int sum=0;
        for(int i=1;i<=n;i++){
            read(f[i]);
            if(f[i]>50){                       //排除 长度大于50的干扰 洛谷的坑点
                n--;
                i--;
            }
            else sum+=f[i];            
        }
        sort(f+1,f+n+1,cmp);                 //剪枝1
        flag=0;
        for(int i=f[1];i<=sum;i++){          //剪枝2
            if(sum%i==0){                    //剪枝3
                memset(vis,0,sizeof vis);
                m=sum/i;
                hhh(0,0,1,i);
                if(flag){
                    cout<<i<<endl;
                    break;
                }
            }
        }
    }
    return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值