2017-03-04 小木棍

Description

乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过50。
现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它们的长度。
给出每段小木棍的长度,编程帮他找出原始木棍的最小可能长度。

Input

共有二行。
第一行为一个单独的整数N表示砍过以后的小木棍的总数,其中N≤60,第二行为N个用空格隔开的正整数,表示N根小木棍的长度。

Output

仅一行,表示要求的原始木棍的最小可能长度。

Sample Input

9
5 2 1 5 2 1 5 2 1

Sample Output

6

Hint

把大于50的略去不管。

Source

搜索

Solution

dfs+优秀的剪枝
搜索就是枚举长木棍的长度(范围是从最长的小木棍长到小木棍总长/2)符不符合要求,这道题中剪枝十分重要; 1.木棍的长度从大到小排序,因为经验告诉我们越长的木棍灵活性越差,所以优先放置长一点的木棍。2.如果当前长度的木棍无法和后面的木棍组成合法的解,那么和它同样长度的木棍一样不能,因此我们可以跳过和它长度相同的木棍。 3. 如果组成原始木棍的第一根木棍无法得出合法解,那么就直接返回不必搜索了,因为以后也不可能得出合法解。

code

#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#define N 61
using namespace std;
int st[N],vis[N];
int n,sum,stsum,maxst,ans;
bool flag;
void dfs(int GoalLength,int DoneSum,int DoneLength,int num)//目标木棍长,已经凑出来的木棍数量,正在凑的这一根木棍已经凑出来的数量,num是小木棍在数组中排序后的长度,为了方便剪枝1
  {
    if(DoneSum==stsum)
      {
    flag=true;ans=GoalLength;return;
      }
    if(flag) return;
    for(int i=num;i>=1;i--)
      if(!vis[i]&&st[i]+DoneLength<=GoalLength)
    {
      vis[i]=1;
      DoneLength+=st[i];
      if(DoneLength==GoalLength) dfs(GoalLength,DoneSum+1,0,st[0]);//凑出了一根,凑下一根,注意这里num要改成st[0]
      else dfs(GoalLength,DoneSum,DoneLength,i-1);//没凑出一根,继续凑,从i-1开始是因为如果长度为st[i]都不能放进去的话,那么比i大的肯定也放不进去
      if(flag) return;
      vis[i]=0;
      DoneLength-=st[i];
      int bobo=st[i];
      if(!DoneLength) return;//剪枝3
      while(i&&st[i]==bobo) i--;//剪枝2
      i++;
    }
  }
int main()
{
  scanf("%d",&n);
  for(int i=1;i<=n;i++)
    {
      int u;
      scanf("%d",&u);
      if(u>50) continue;//这里注意一定要过滤掉长度大于50的木棍
      st[++st[0]]=u;//用st[0]计符合要求的小木棍数
      sum+=u;
      maxst=max(maxst,u);
    }
  int i;
  sort(st+1,st+st[0]+1);
  for(i=maxst;i<=sum/2;i++)//从最长的一根小木棍的长度开始枚举长度,最大为sum/2,即这些小木棍最少是从两根长木棍切出来的
    {
      memset(vis,false,sizeof(vis));
      if(sum%i) continue;//如果不能整除,那么肯定拼不出来,跳过就好
      flag=false;
      stsum=sum/i;//长木棍长度为i时,有stsum条长木棍
      dfs(i,0,0,st[0]);
      if(flag)//如果成立
    break;
    }
  if(i>sum/2) printf("%d\n",sum);
  else printf("%d\n",ans);
  return 0;
}

其实吧,这道题,直接输出sum/n,就有30分
如果,过滤掉大于50的小木棍,再输出average值,就有80分了噢

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值