HDU 1455 Sticks

来源:互联网 发布:丁丁软件如何使用 编辑:程序博客网 时间:2024/05/20 01:12

题意:
给你n个不超过50的长度,它们是一根或多跟棍子(长度都相同)的一部分,求符合条件的棍子的最短长度。
思路:
这道题里面分组的思路真是经典,剪枝的思路也是很有趣。
首先从这些长度里面的最大的长度开始遍历(因为棍子的长度肯定不小于最大的长度),看这个长度的棍子是否能被组成。
至于具体剪枝看代码里面的注释吧。
Code:

#include<cstring>#include<cstdlib>#include<cstdio>#include<cctype>#include<cmath>#include<algorithm>#include<iostream>#include<string>#include<vector>#include<bitset>#include<queue>#include<stack>#include<list>#include<map>#include<set>#define TEST#define Mt(f, x) memset(f, x, sizeof(f));#define LL long long#define rep(i, s, e) for(int i = (s); i <= (e); ++i)#ifdef TEST    #define See(a) cout << #a << " = " << a << endl;    #define See2(a, b) cout << #a << " = " << a << ' ' << #b << " = " << b << endl;    #define debug(a, s, e) rep(_i, s, e) {cout << a[_i] << ' ';} cout << endl;    #define debug2(a, s, e, ss, ee) rep(i_, s, e) {debug(a[i_], ss, ee);}#else    #define See(a)    #define See2(a, b)    #define debug(a, s, e)    #define debug(a, s, e, ss, ee)#endif // TESTconst int MAX = 2e9;const int MIN = -2e9;const double eps = 1e-8;const double pi = acos(-1.0);using namespace std;const int N = 75;int a[N];bool v[N];//记录每个长度是否被用过了int n;bool dfs(int t, int add, int sum, int tsum)//t代表上次搜索的长度的编号,add已经累积的长度,sum要组成棍子的长度,tsum剩余需要组成的长度{    if(sum == tsum)//剩余的长度等于要找的长度,那么就已经找到了    {        return true;    }    if(add == sum)//如果已经累积的长度等于要找的长度,就直接再从头找下一根棍子    {        return dfs(-1, 0, sum, tsum - sum);    }    for(int i = t + 1; i < n; ++i)    {        if(v[i])//如果用过了,就用下一个        {            continue;        }        if((sum - add) / a[i] > n - t)//由于我们对长度已经排过序了,所以长度必定是不递减的,如果以后的都是当前长度的,还组不成一根棍子,就返回false        {            return false;        }        if(add + a[i] <= sum)//如果累积的和此根棍子和小于等于要组成的棍子长度        {            v[i] = true;//记录用过了            if(dfs(i, add + a[i], sum, tsum))//如果找到了返回true            {                return true;            }            v[i] = false;            if(add + a[i] < sum && add == 0)//如果这个长度组不成一根棍子,并且以前没有累积的数值,就说明以后只要包含这根棍子的组合都不符合,那就可以直接返回false                return false;            if(add + a[i] == sum)//如果这个长度组成棍子不成功,那么剩下和它一样长度的也组不成棍子            {                while(a[i] == a[i + 1]) i++;            }        }    }    return false;}int main(){    while(~scanf("%d", &n) && n)    {        int tsum = 0;        for(int i = 0; i < n; ++i)        {            scanf("%d", &a[i]);            tsum += a[i];        }        sort(a, a + n, greater<int>()); //根据长度从大到小排序,以后就可以方便的剪枝        for(int i = a[0]; i <= tsum; ++i) //从最长的开始遍历,到他们的总和        {            if(tsum % i == 0) //如果总长度能被这个长度整除,那么有可能符合条件,因为棍子的长度都是相同的            {                Mt(v, false);                if(dfs(-1, 0, i, tsum))                {                    printf("%d\n", i);                    break;                }            }        }    }    return 0;}
0 0