一.题目链接:
POJ-1011
二.题目大意:
给你 n 个小木棍,要求将其中不超过 50 长度的木棍拼成若干个木棒.
并且使木棒的长度均相同,最后输出木棒的最小长度.
三.分析:
这道 dfs 剪枝快剪成 了。。。
①:确定答案的的范围:答案必定比最长木棍长 且 必定为不超过 50 木棍长度和的约数.
②:优化搜索顺序.
③:vis 标记去重 + 最优性剪枝 + 排除等效冗余剪枝.
④:空木棒的等效剪枝 + 贪心剪枝.
详见代码.
四.代码实现:
#include <set>
#include <map>
#include <ctime>
#include <queue>
#include <cmath>
#include <stack>
#include <bitset>
#include <vector>
#include <cstdio>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define eps 1e-8
#define lc k * 2
#define rc k * 2 + 1
#define pi acos(-1.0)
#define ll long long
#define ull unsigned long long
using namespace std;
const int M = (int)1e2;
const int mod = 99991;
const int inf = 0x3f3f3f3f;
int a[M + 5];
bool vis[M + 5];
int n, m, x, sum, len, cnt;
bool cmp(int a, int b)
{
return a > b;
}
bool dfs(int num, int have, int last)
{
if(num > cnt)
return 1;
if(have == len)
return dfs(num + 1, 0, 1);
int fail = 0;
for(int i = last; i <= n; ++i)
{
if(!vis[i] && have + a[i] <= len && fail != a[i])
{
vis[i] = 1;
if(dfs(num, have + a[i], i + 1))
return 1;
vis[i] = 0;
fail = a[i];
if(!have || have + a[i] == len)
return 0;
}
}
return 0;
}
int main()
{
while(~scanf("%d", &n) && n)
{
m = sum = len = 0;
for(int i = 1; i <= n; ++i)
{
scanf("%d", &x);
if(x > 50) continue;
a[++m] = x;
sum += x;
len = max(len, x);
}
n = m;
sort(a + 1, a + n + 1, cmp);
for( ; ; ++len)
{
if(sum % len) continue;
cnt = sum / len;
memset(vis, 0, sizeof(vis));
if(dfs(1, 0, 1)) break;
}
printf("%d\n", len);
}
return 0;
}