毫无疑问,非常经典的搜索题。除了在搜索前要对木棍进行排序外,在搜索过程中的两个关键的剪枝必须要考虑到,否则就TLE了:
(1)在当前尚未组合的木棍里面,先把第一条尚未组合的木棍做为原始木棍的一部分,然后尝试搜索填充这条原始木棍的剩余部分,若失败,则直接返回上一层。
(2)若当前木棍参与当前的组合方式不能得到合法的解,那么后面的长度和这条木棍相同的木棍可以直接跳过。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
vector<int> sticks;
vector<bool> flags;
int sumLen ;
int len;
bool Comp(int left, int second)
{
return left > second;
}
bool Dfs(bool first, int b, int l, int n)
{
if( n == 1 )
return true;
int i = b;
while( i < sticks.size() )
{
if(!flags[i] && l >= sticks[i])
{
flags[i] = true;
bool ans = (l == sticks[i])?Dfs(true, 0, len, n-1): \
Dfs(false, i+1, l-sticks[i], n);
if( ans )
return true;
flags[i] = false;
if( first )
return false;//剪枝(1)
while(sticks[i] == sticks[i+1])//剪枝(2)
++i;
}
++i;
}
return false;
}
int main()
{
int num;
while( cin >> num && num )
{
sticks.clear();
sumLen = 0;
int maxLen = 0;
for(int i = 0; i < num; ++i)
{
int temp;
cin >> temp;
if( maxLen < temp )
maxLen = temp;
sumLen += temp;
sticks.push_back(temp);
}
sort(sticks.begin(), sticks.end(), Comp);
flags.assign(sticks.size(), false);
len = maxLen ;
while( len <= sumLen )
{
flags.assign(sticks.size(), false);
if( !(sumLen%len) && Dfs(true, 0, len, sumLen/len) )
{
cout << len << endl;
break;
}
++len;
}
}
return 0;
}
bool Dfs(int b, int l, int n)
{
if( n == 1 )
return true;
if( !l )
{
int i = 0;
while( flags[i] )
++i;
flags[i] = true;
bool ans = Dfs(i+1, len-sticks[i], n-1);
if( ans )
return true;
flags[i] = false;
return false;
}
int i = b;
while( i < sticks.size() )
{
if(!flags[i] && l >= sticks[i])
{
flags[i] = true;
bool ans = Dfs(i+1, l-sticks[i], n);
if( ans )
return true;
flags[i] = false;
while(sticks[i] == sticks[i+1])
++i;
/*
flags[i] = true;
if(l == sticks[i])
{
int j = 0;
while( flags[j] )
++j;
flags[j] = true;
if( Dfs(j+1, len-sticks[j], n-1) )
{
return true;
}
flags[j] = false;
flags[i] = false;
return false;
}
else
{
bool ans = Dfs(i+1, l-sticks[i], n);
if( ans )
return true;
flags[i] = false;
while(sticks[i] == sticks[i+1])
++i;
}
*/
}
++i;
}
return false;
}