题目链接:http://www.acm.cs.ecnu.edu.cn/problem.php?problemid=1981
题意:原本有一些等长的木棍,然后他们被弄断了。现在你想把他们恢复,但是不知道原本的长度和根数。现在希望恢复的原木棍长度越短越好。
分析:
使用迭代加深搜索。枚举原本木棍的长度进行搜索。需要加以下剪枝方案。
1,排序后由大到小枚举每根木棍,因为每根木棍都会被使用,优先选取大的可以减少递归深度。
2,待拼木棍长度为总长度的约数。
3,若有相同长度木棍在之前没有被选取,则之后不用再考虑此木棍。
4,若无法拼出长度<=SUM/2的小木棍,则只能拼出长度为sum的小木棍。
5,若当前剩余第一根木棍无法使用则说明无法完成任务可提前结束dfs,因为每根木棍都会被使用。
6,若待拼木棍长度为当前小木棍长度,则说明此木棍为最后一根小木棍。若在选取了当前这根小木棍还无法完成任务,则这根小木棍无法被使用,同样结束程序。
7,限制递归调用深度。
(该代码重写过,详见http://blog.csdn.net/u013520118/article/details/48417565)
代码:
#include <iostream>
#include <algorithm>
#include <fstream>
#include <cstring>
#include <vector>
#include <queue>
#include <cmath>
#include <cctype>
#include <stack>
#include <set>
using namespace std;
const int maxn = 100 + 5;
bool flag;
int n, sum, deep;
int a[maxn], v[maxn];
bool cmp(const int& x, const int& y)
{
return x > y;
}
bool DFS(int cur, int left, int limit)
{
if (deep++ > 200000)
return false;
if (!cur && !left)
return true;
if (!left)
left = limit;
for (int i = 0; i < n; ++i)
{
if (i > 0 && a[i] == a[i - 1] && !v[i - 1])
continue;
if (!v[i] && a[i] <= left)
{
v[i] = 1;
if (DFS(cur - 1, left - a[i], limit))
return true;
else
{
v[i] = 0;
if (a[i] == left || left == limit)
return false;
}
}
}
return false;
}
int main()
{
while (~scanf("%d", &n), n)
{
sum = 0;
flag = false;
for (int i = 0; i < n; ++i)
{
scanf("%d", &a[i]);
sum += a[i];
}
sort(a, a + n, cmp);
for (int i = a[0]; i <= sum / 2; ++i)
if (sum % i == 0)
{
deep = 0;
memset(v, 0, sizeof(v));
if (DFS(n, i, i))
{
flag = true;
printf("%d\n", i);
break;
}
}
if (!flag)
printf("%d\n", sum);
}
return 0;
}