I - 剪枝 0。O HDU - 1455 Sticks DFS

I - 剪枝 0。O HDU - 1455 

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

题意:输入n个整数,把这n给整数分成m堆,使得这m堆每一堆的和都相等,求最小的和

思路:因为数据很小,所有可以直接枚举和,搜索是否可行,考点在剪枝

#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <cmath>
#include <algorithm>
#include <string>
#include <map>
#include <stack>
#include <set>
typedef long long LL;
using namespace std;
const int maxn=111;
int n;
int suma=0,maxa=0;
int a[maxn],vis[maxn];
bool cmp(int a,int b)
{
    return a>b;
}
bool DFS(int len,int need_len,int x)//和为len,还需need_len,还有x个数字没用
{
    if(x==0)
    {
        printf("%d\n",len);
        return true;
    }
    if(need_len==0)//准备构成新的len
        need_len=len;
    for(int i=0;i<n;i++)
    {
        if(!vis[i])//没被用过
        {
            if(need_len>=a[i])
            {
                vis[i]=1;
                if(DFS(len,need_len-a[i],x-1))return true;//把a[i]放到当前堆里
                vis[i]=0;
                if(a[i]==need_len||need_len==len)return false;/*剪枝
                到这里是放入a[i]不能构成len
                1.如果此时a[i]==need_len,说明放入a[i]可以构成一个新的len,但是没有成功
                  要继续下去的话,就是将这个a[i]变成其他的几个之和,然后在后面构成的新的len里用a[i],
                  但因为每个数字都必须且只能使用一次,所以使用a[i]和几个数之和等于a[i]的其实是一样的,
                  所以如果这样不能成功,当前的路不通
                  而且这里不用a[i]后面也要用,还不如先用,留下那几个小的数构成后面的更灵活
                2.need_len==len,说明正准备进行新一轮的组合,但是新的len却不能构造成功,即即是说加入a[i]的话,
                  剩下的数不能构造出len,但是a[i]一定要用上,所以可知当前的路不通
                */
                int j=i;
                while(i<n&&a[j]==a[i])//剪枝,相同的不重复计算
                    i++;
                i--;
            }
        }
    }
    return false;
}
int main()
{
    while(~scanf("%d",&n)&&n)
    {
        suma=0,maxa=0;
        memset(vis,0,sizeof(vis));
        for(int i=0;i<n;i++)
        {
            scanf("%d",&a[i]);
            suma+=a[i];
            maxa=max(maxa,a[i]);
        }
        sort(a,a+n,cmp);
        for(int i=maxa;i<=suma;i++)
        {
            if(suma%i!=0)
                continue;
            memset(vis,0,sizeof(vis));
            if(DFS(i,i,n))break;
        }
    }
    return 0;
}

 

posted on 2018-08-01 12:20  一零七  阅读(82)  评论(0编辑  收藏  举报

导航