洛谷 【P1120】 小木棍

P1120 小木棍
传送门
标签搜索/枚举
难度普及+/提高
通过/提交255/1689
提交该题 讨论 题解 记录
题目描述
乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过50。
现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它们的长度。
给出每段小木棍的长度,编程帮他找出原始木棍的最小可能长度。
输入输出格式
输入格式:
输入文件共有二行。
第一行为一个单独的整数N表示砍过以后的小木棍的总数,其中N≤60
(管理员注:要把超过50的长度自觉过滤掉,坑了很多人了!)
第二行为N个用空个隔开的正整数,表示N根小木棍的长度。
输出格式:
输出文件仅一行,表示要求的原始木棍的最小可能长度
输入输出样例
输入样例#1:
9
5 2 1 5 2 1 5 2 1
输出样例#1:
6

此题没有思路所以卡点只过了2个。
求教神犇后————————————————
这题深搜加枚举;
首先要先去掉大于50的数,
从大到小排序,将所有木棍的值加起来,要求的木棍长度一定在单个木棍的最大值(maxx)和所有总木棍长度(sum)之间,for枚举maxx—>sum,进行深搜(深搜过程看代码)。
由于数据较大,深搜时要不断剪枝,防止超时爆点。

代码如下:

#include<cstdio>
#include<iostream>
#include<algorithm>
int n,cnt,sum,maxx,flag,t,m;
int a[100];
bool b[100];
using namespace std;
int cmp(const int&a,const int&b)
{
    return a>b;
}
void dfs(int l,int s,int p)//l代表目前找了几根木棍
                        //s代表目前木棍的长度
                        //p用于减少循环次数
{
    if(flag) return;
    if(s==m)
      {  
        s=0;
        l++;
        p=0;
      }
    if(l==t-1)//剪枝  s-m*(t-1)=m 可推出l==t-1时 木棍长度符合条件
      {
        flag=1;
        return;
      }
    for(int i=p+1;i<=cnt;i++)
      {
        if(s+a[i]>m||b[i]) continue;
        if(a[i]==a[i-1]&&!b[i-1]) continue;
        b[i]=1;
        dfs(l,s+a[i],i);
        b[i]=0;
        if(flag)return;
        if(s==0)return;//如果第一根木棍不符合,后面的都不符合,所以枚举的长度
                      //就不对,直接退出,减少时间。
      }
    if(flag)return;
}
int init()
{
    int x;
    for(int i=1;i<=n;i++)
      {
        cin>>x;
        if(x<=50)
          {
            a[++cnt]=x;
            sum+=x;//总长度
            maxx=max(maxx,x);//单个最大值
          }
      }
}
int main()
{
    cin>>n;
    init();
    sort(a+1,a+n+1,cmp);//从大到小排序,便于匹配
    for(int i=maxx;i<=sum;i++)
      {
        if(sum%i==0)
          {
            t=sum/i;
            m=i;
            flag=0;
            dfs(0,0,0);
            if(flag)
              {
                 cout<<i<<endl;
                 return 0;
              }
          }
      }
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值