zoukankan      html  css  js  c++  java
  • 牛客

    链接:https://ac.nowcoder.com/acm/problem/50243
    来源:牛客网

    时间限制:C/C++ 1秒,其他语言2秒
    空间限制:C/C++ 32768K,其他语言65536K
    64bit IO Format: %lld

    题目描述

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

    输入描述:

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

    输出描述:

    输出仅一行,表示要求的原始木棍的最小可能长度。
    示例1
    输入
    9
    5 2 1 5 2 1 5 2 1
    输出
    6
    备注:
    1<=N<=60

    题目大意:
    给出n个小木棍,你的任务是把他们拼接起来,还原原来的木棍,求拼接后每个小木棍的最小长度。

    解题思路:
    这个题注意一定要用搜索做而不是二分,之前做过一个拆分木棍的题是二分,因为那个题长度和拆分的数量有一个线性关系,而这个合并木棍并没有,我们用DFS+剪枝AC这个题,因为要求最小的长度,我们先将木棍排序,因为要求拼成的最小的长度,我们要从这些木棍最长的开始往上枚举,对每一个枚举的长度进行搜索,搜索的状态是(剩余木棍的个数,枚举的长度,当前拼成木棍剩余长度,和当前枚举的哪一根木棍)另外需要剪枝操作,剪枝有以下几点:

    1. 如果当前木棍是当去拼枚举长度的第一根,则需要剪掉,因为我们从最长的开始枚举,如果连第一个都拼不上,那么后面的肯定也拼不上。
    2. 如果当前木棍是当去拼枚举长度的最后一根,也需要剪掉,因为木棍是从大到小排,如果这个长度都不行,那后面的长度肯定比这个还小,肯定也拼不上,剪掉。
    3. 如果当前小木棍拼不上,那么和当前木棍长度相同的木棍肯定也拼不上,直接过滤掉和当前木棍长度相等的木棍即可。

    AC代码:

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    const int N = 65;
    int a[N],n;
    bool vis[N];
    bool cmp(int a,int b) { return a>b; }
    bool dfs(int num,int len,int rest,int now)
    {
        if(num==0&&rest==0)//当前剩余0个木棍且当前要拼的长度为0时代表可以拼成
          return true;
        if(rest==0)
          rest=len,now=0;
        for(int i=now;i<n;i++)
        {
            if(a[i]>rest)
              continue;
            if(!vis[i])
            {
                vis[i]=true;
                if(dfs(num-1,len,rest-a[i],i+1))
                  return true;
                vis[i]=false;
                if(a[i]==rest||len==rest)//第一个木棍和最后一个木棍的时候剪掉
                  break;
                while(a[i]==a[i+1])//过滤掉相同的木棍
                  i++;
            }
        }
        return false;
    }
    int main()
    {
        int sum=0,s=0;
        scanf("%d",&n);
        memset(vis,false,sizeof vis);
        for(int i=0;i<n;i++)
        {
            scanf("%d",&a[i]);
            if(a[i]<=50)
              sum+=a[i];
            else
              s++;  
        }
        n-=s;
        sort(a,a+n,cmp);
        for(int i=a[0];i<=sum;i++)//从最大的开始枚举
        {
            if(sum%i==0)
              if(dfs(n,i,0,0))
              {
                  printf("%d
    ",i);
                  break;
              }
        }
        return 0;
    }
    
  • 相关阅读:
    [Spark内核] 第38课:BlockManager架构原理、运行流程图和源码解密
    [Spark内核] 第37课:Task执行内幕与结果处理解密
    [Spark内核] 第36课:TaskScheduler内幕天机解密:Spark shell案例运行日志详解、TaskScheduler和SchedulerBackend、FIFO与FAIR、Task运行时本地性算法详解等
    [Spark内核] 第35课:打通 Spark 系统运行内幕机制循环流程
    [Spark性能调优] 第三章 : Spark 2.1.0 中 Sort-Based Shuffle 产生的内幕
    [Spark内核] 第34课:Stage划分和Task最佳位置算法源码彻底解密
    spring boot 日志收集整理
    mybatis 使用redis实现二级缓存(spring boot)
    MD5收集整理
    IntelliJ IDEA 2019.2最新版本免费激活码
  • 原文地址:https://www.cnblogs.com/Hayasaka/p/14294259.html
Copyright © 2011-2022 走看看