拯救少林神棍
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <memory.h>
#include <stdlib.h>
#include <vector>
#include <algorithm>
#include <functional> // std::greater
using namespace std;
int T, N;
int L;
int nLastStickNo;//最近拼上去的那条木棒的下标
vector<int> anLength;
int anUsed[65];//是否用过的标记
int i, j, k;
int Dfs(int R, int M);
int main()
{
while (1) {
cin >> N;
if (N == 0)
break;
int nTotalLen = 0;
anLength.clear();
for (int i = 0; i < N; i++) {
int n;
cin >> n;
anLength.push_back(n);
nTotalLen += anLength[i];
}
sort(anLength.begin(), anLength.end(), greater<int>());
//从最长的第一根小棒开始,直到总长度的一半
for (L = anLength[0]; L <= nTotalLen / 2; L++) {
if (nTotalLen % L)//如果不可以全拼完 ,L长度就不是
continue;
memset(anUsed, 0, sizeof(anUsed));
if (Dfs(N, L)) {
cout << L << endl;
break;
}
}
if (L > nTotalLen / 2)//如果大于小棒总长度的一半 输出总长度
cout << nTotalLen << endl;
} // while
return 0;
}
//nUnusedSticks 还剩小棍数量
int Dfs(int nUnusedSticks, int nLeft)
// nLeft表示当前正在拼的棍子和 L 比还缺的长度
{
if (nUnusedSticks == 0 && nLeft == 0)
return true;
if (nLeft == 0) //一根刚刚拼完
nLeft = L; //开始拼新的一根
int nStartNo = 0;
if (nLeft != L) //剪枝4
nStartNo = nLastStickNo + 1;//nLastStickNo 最近拼上去的那条木棒的下标
for (int i = nStartNo; i < N; i++) {//遍历所有小棍
if (!anUsed[i] && anLength[i] <= nLeft) {//没有被使用过且 小于棒子还差的长度
if (i > 0) {//不是第一根
if (anUsed[i - 1] == false
&& anLength[i] == anLength[i - 1])//前一根没有被使用 且长度一样
continue; //剪枝1
}
anUsed[i] = 1; nLastStickNo = i;
if (Dfs(nUnusedSticks - 1,
nLeft - anLength[i]))
return true;
else {
anUsed[i] = 0;//说明本次不能用第i根
//第i根以后还有用
if (anLength[i] == nLeft || nLeft == L)
return false;//剪枝3、2
}
}
}
return false;
}