#include <bits/stdc++.h> using namespace std; const int maxn = 65; int n, sum, goal, stick[maxn]; bool visit[maxn]; bool dfs(int now, int index, int cnt) { if (goal * cnt == sum) return 1; for (int i = index ; i < n; i++) { if (visit[i] || (i && !visit[i - 1] && stick[i] == stick[i - 1])) continue; if (now + stick[i] == goal) { visit[i] = 1; if (dfs(0, 0, cnt + 1)) return 1; visit[i] = 0; return false; } else if (now + stick[i] < goal) { visit[i] = true; if (dfs(now + stick[i], i + 1, cnt)) return 1; visit[i] = false; if (now == 0) return 0; } } return 0; } int solve() { sort(stick, stick + n, greater<int>()); for (goal = stick[0]; goal < sum; goal++) { if (sum % goal != 0) continue; memset(visit, 0, sizeof(visit)); if (dfs(0, 0, 0)) break; } return goal; } int main(int argc, char const *argv[]) { while (cin >> n && n) { sum = 0; for (int i = 0; i < n; i++) { cin >> stick[i]; sum += stick[i]; } cout << solve() << endl; } return 0; }
贴别人的题解http://www.cppblog.com/y346491470/articles/155318.html
【题解】:不得不说,这道题出得非常好,特别是uva那里的大数据(poj的数据太水了),对于剪枝能力要求很高。下面说下几个重要的剪枝:
1.把所有木棍的长度从大到小排列,组合木棒时优先使用长的木棍,这样可以加快组合速度,并且对后面的剪枝有帮助。
2.木棒的长度一定是大于等于最长木棍的长度并且小于等于所有木棍长度的和,这个很容易证明。
3.木棒的长度一定是所有木棍长度的和的约数,这个也很容易证明。
4.在某一个木棒的组合过程中,对于当前的木棍stick[i],如果stick[i-1]没有被组合并且stick[i] == stick[i-1],那么不用考虑stick[i],显然stick[i]最终也不会被组合。
5.如果此次是在尝试第i个木棒的第一段,假设stick[j]为当前可以被使用的最长的木棍,如果此次组合失败,直接退出搜索,即退回到对第i-1个木棒的搜索。试想:失败说明现在使用stick[j]是不可行的,那么以后无论什么时候使用stick[j]都是不可行的,因为以后再处理stick[j]时可使用的木棍一定是当前可使用的木棍的子集,在更多木棍选择的情况下都不能组合成功,那么,在更少木棍选择的情况下一定不能组合成功。