hdu1455

Sticks

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 10482    Accepted Submission(s): 3151


Problem Description
George took sticks of the same length and cut them randomly until all parts became at most 50 units long. Now he wants to return sticks to the original state, but he forgot how many sticks he had originally and how long they were originally. Please help him and design a program which computes the smallest possible original length of those sticks. All lengths expressed in units are integers greater than zero.
 

Input
The input contains blocks of 2 lines. The first line contains the number of sticks parts after cutting, there are at most 64 sticks. The second line contains the lengths of those parts separated by the space. The last line of the file contains zero.
 

Output
The output file contains the smallest possible length of original sticks, one per line.
 

Sample Input
  
  
9 5 2 1 5 2 1 5 2 1 4 1 2 3 4 0
 

Sample Output
  
  
6 5
 

Source

 

思路:dfs加剪枝

具体思想写在注释上了

//我是先做了 hdu那个判断能不能组成正方形的来做这个的,这两个题的思路是一样的,但是这个题的剪枝比那个题的剪枝要多
//首先我们要确定棍子的大小的范围, 最小 不会比断的棍子的最大小,最大不会大过断棍子的和。这就是范围;枚举上去就行。
//然后就是剪枝了,第一个剪枝,判断 能不能整除枚举的棍子的大小,第二个剪枝,我们排好序去做,如果相同长度的棍子第一根不匹配时
//后面直接可以跳过。
//第二个剪枝这里也是关键的剪枝, 当sun(已经匹配了棍子的长度) =0时,而且 第一根棍子又没有成功匹配的时候,那么这种匹配就是不行的
//怎么说呢 假如我们继续匹配,当第二根棍子 又会去跟第一根匹配,但是之前第一根已经跟第二根匹配过了,并且没有成功。所以这种匹配是错误的

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int n;
int a[65],sum,sum1,xx;
int vis[65];
int cmp(const void *a, const void *b)
{   //return *(int*)a  -  *(int*)b; //由小到大排序
    return *(int*)b -*(int*)a ;  //由大到小排序
}
int dfs(int sum,int k,int count)//sum1表示长棍子的长度,sun这里表示已经把断棍子组合起来有了多少长度,count表示已经组合了多少根,k表示从那根开始匹配。
{
    if(sum==sum1)//假如匹配到断棍子的长度跟 要找的长度一样 则 计数器加1,又开始继续重新匹配。
    {
       sum=0,count++,k=1;
    }
    if(count==xx-1) return 1;//一共要匹配xx跟 但是只要匹配xx-1根就行了
    for(int i=k;i<=n;i++)
    {
        if(!vis[i]&&sum+a[i]==sum1)
        {
            vis[i]=1;
            if(dfs(sum+a[i],i+1,count)) return 1;//当有棍子组合起来与他相等,则匹配,如果这种情况不行那后面的加起来比他小的也肯定不行了,为什么呢。假如第一根是5
                                                //要匹配的长度也是5 所以就进去,然后这都匹配不成功 说明长度为5不行,就拿第二个示例而言。
            vis[i]=0;
            return 0;
        }
    }
    for(int i=k;i<=n;i++)
    {
        if(!vis[i]&&sum+a[i]<sum1)
        {
            vis[i]=1;
            if(dfs(sum+a[i],i+1,count)) return 1;
            vis[i]=0;
            if(sum==0) return 0;//这里就是第一行注释的第三个剪枝,当要匹配的棍子第一根没有成功的时候那么后面第二根又跟第一根匹配 又不会成功。
            while(a[i]==a[i+1]) i++;

        }
    }
    return 0;
}
int main()
{
    while(scanf("%d",&n)&&n)
    {  int max=-1,sum=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            sum+=a[i];
            if(max<a[i]) max=a[i];
        }
        int i=max;
        qsort(&a[1],n,sizeof(int),cmp);
        while(i<=sum)
        {   //printf("aa");
            if(sum%i!=0){ i++;continue;}
            xx=sum/i;
            sum1=i;
            memset(vis,0,sizeof(vis));
            if(dfs(0,1,0))
            {
                break;
            }
            i++;

        }
        printf("%d\n",i);
    }
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值