# POJ 1011 Sticks（搜索问题）

#include <iostream>
#include <algorithm>
#include <cstdio>

using namespace std;

int N, flag;
int stick[68];
int group[64];      // 每一分组暂时的和

bool cmp(int a, int b)
{
return a>b;
}

void f(int index, int g_num, int max_num)
{
// 判断是否超出每一组最大值
int judge = 1;
for(int i=0;i<g_num;i++)
{
if(group[i] != max_num)
{
judge = 0;
break;
}
}
if(judge == 1)      // 已经确定这样分组可行
{
flag = 1;
return;
}

// 对元素i，枚举它属于的组数
for(int i=0;i<g_num;i++)
{
if(group[i]+stick[index] <= max_num)
{
group[i] += stick[index];
f(index+1, g_num, max_num);
group[i] -= stick[index];
}
}
}

int main()
{
while(scanf("%d", &N) && N>0)
{
int tot = 0, max_ele = -9999;   // 枚举的范围
// 输入stick的值
for(int i=0;i<N;i++)
{
scanf("%d", &stick[i]);
max_ele = max(max_ele, stick[i]);
tot += stick[i];
}

sort(stick, stick+N, cmp);

// 最终应该有 tot/i 组
for(int i=max_ele;i<=tot;i++)
{
flag = 0;       // 标记这样分配是否可以
if(tot%i != 0)
continue;
for(int j=0;i<tot/i;j++)
group[j] = 0;
f(0, tot/i, i);

if(flag == 1)
{
printf("%d\n", i);
break;
}
}

}
return 0;
}

#include <iostream>
#include <algorithm>
#include <cstdio>

using namespace std;

int N, flag;
int stick[68];
int vis[68];

bool cmp(int a, int b)
{
return a>b;
}

void dfs(int tot_used, int now_len, int now_stick, int each_len)
{
if(flag == 1)
return;
if(now_len == 0)        // 找到下一个开头的小棒
{
for(int i=0;i<N;i++)
{
if(vis[i] == 0)
{
vis[i] = 1;
dfs(tot_used+1, stick[i], i+1, each_len);
vis[i] = 0;
return;
}
}
}

if(now_len == each_len)     // 又拼好一根
{
if(tot_used == N)
{
flag = 1;
return;
}
dfs(tot_used, 0, 0, each_len);      // 再重新开始拼接
return;
}

for(int i=now_stick;i<N;i++)
{
if(vis[i]==0 && now_len + stick[i] <= each_len)
{
if(vis[i-1]==0 && stick[i] == stick[i-1])
continue;      //  不重复搜索：最重要的剪枝。前一根和他一样的，拼不起来，那它也不用试了
vis[i] = 1;
dfs(tot_used+1, now_len + stick[i], i + 1, each_len);
vis[i] = 0;
}
}
}

int main()
{
while(scanf("%d", &N) && N>0)
{
int tot = 0, max_ele = -9999;   // 枚举的范围
// 输入stick的值
for(int i=0;i<N;i++)
{
scanf("%d", &stick[i]);
max_ele = max(max_ele, stick[i]);
tot += stick[i];
vis[i] = 0;
}

sort(stick, stick+N, cmp);      // 降序排序

// 最终应该有 tot/i 组
for(int i=max_ele;i<=tot;i++)
{
flag = 0;       // 标记这样分配是否可以
if(tot%i != 0)
continue;
//f(0, tot/i, i);
dfs(0, 0, 0, i);

if(flag == 1)
{
printf("%d\n", i);
break;
}
}

}
return 0;
}