您的位置:首页 > 其它

HDU 1455 Sticks

2015-04-12 17:59 375 查看
题意:

给你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 // TEST

const 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
;
bool v
;//记录每个长度是否被用过了
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: