zoukankan      html  css  js  c++  java
  • P1120 小木棍 [数据加强版](poj 1011)

    题目描述

    乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过50。

    现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它们的长度。

    给出每段小木棍的长度,编程帮他找出原始木棍的最小可能长度。

    输入输出格式

    输入格式:

    输入文件共有二行。

    第一行为一个单独的整数N表示砍过以后的小木棍的总数,其中N≤65

    (管理员注:要把超过50的长度自觉过滤掉,坑了很多人了!)

    第二行为N个用空个隔开的正整数,表示N根小木棍的长度。

    输出格式:

    输出文件仅一行,表示要求的原始木棍的最小可能长度

    输入输出样例

    输入样例#1: 
    9
    5 2 1 5 2 1 5 2 1
    
    输出样例#1: 
    6

    说明

    2017/08/05

    数据时限修改:

    -#17 #20 #22 #27 四组数据时限500ms

    -#21 #24 #28 #29 #30五组数据时限1000ms

    其他时限改为200ms(请放心食用)

    Solution:

    本题就是纯考搜索和剪枝了,在看lyd的书时看到了这题,于是来写一写,结果lyd的思路还过不了这题,但剪枝的思想值得借鉴。

    首先就是说说这题的坑点:注意木棍长度不大于50,所以输入的木棍长度中要忽略长度超过50的木棍,这我被坑了啊。

    再来说说解题思路,搜索时从小到大枚举原木棍长度,显然(木棍最大长度≤原木棍长度≤木棍总长度),然后搜索判断情况能否可行。

    然后就来说说最最重要的剪枝吧:

    1、优化顺序,dfs判断情况时从最长的木棍枚举到最短的木棍,因为能与最长的木棍组成当前需要的长度的木棍的个数显然要比长度短的少,能减少分枝数。因为长度不超过50,于是没必要对木棍长度快排,而是直接桶排,常数小且方便判断和回溯。

    2、木棍个数应该为整数,所以枚举的长度应该能整除总长度。

    3、若当前搜索时已经使用了长度为x的木棍,则下次直接从长度为x从大到小枚举,因为显然比x长的都不可行了,否则当前就不会使用x了。

    4、若某次搜索拼接时,当前拼好的长度为0或当前长度加上先前枚举的长度等于需要长度,直接跳出循环,因为我们是递减枚举,显然再往后搜不能再从那些长度小的木棍中拼出当前的长度。

    代码:

    #include<bits/stdc++.h>
    #define il inline
    #define ll long long
    #define N 100
    using namespace std;
    int n,a[N],tmp[N],maxn,minn=N,cnt;
    il void dfs(int res,int now,int len,int p)
    {
        if(!res){printf("%d",len);exit(0);}
        if(now==len){dfs(res-1,0,len,maxn);return;}
        for(int i=p;i>=minn;i--)
            if(tmp[i]&&i+now<=len){
                tmp[i]--;
                dfs(res,i+now,len,i);
                tmp[i]++;
                if(!now||now+i==len)break;
            }
        return;
    }
    int main()
    {
        scanf("%d",&n);
        int x,sum=0;
        while(n--){
            scanf("%d",&x);
            if(x<=50){
                a[++cnt]=x;
                maxn=maxn>x?maxn:x;
                minn=minn<x?minn:x;
                tmp[x]++;sum+=x;
            }
        }
        x=sum>>1;
        for(int i=maxn;i<=x;i++)
            if(sum%i==0)dfs(sum/i,0,i,maxn);
        cout<<sum;
        return 0;
    }
  • 相关阅读:
    NAT基本原理及应用
    端口转发和端口映射的区别
    Xshell不能连接Kali系统SSH的解决
    PowerSploit
    powertool
    Windows/Linux 下反弹shell
    Apache Shiro 反序列化漏洞复现(CVE-2016-4437)
    渗透测试神器Cobalt Strike使用教程
    Notepad++ 小技巧
    Linux:Day44(上)
  • 原文地址:https://www.cnblogs.com/five20/p/8587579.html
Copyright © 2011-2022 走看看