这道题收获还是挺大的。
就是把一堆长度不一的stick拼成长木棍,要求所有长木棍长度相同且使长度最短。
未说明数据规模,可能n会比较大。
我的第一个版本是抱着侥幸心理写的,用的next_permutation对所有stick进行排列,依次计算能否组成特定长度,显然在n较大时会超时,这个就不多说了,不过了解了next_permutation的工作原理:
next_permutation根据标记从后往前比较相邻两数据,若前者小于(默认为小于)后者,标志前者为X1(位置PX)表示将被替换,再次重后往前搜索第一个不小于X1的数据,标记为X2。交换X1,X2,然后把[PX+1,last)标记范围置逆。完成。
这样做的原理是,从位置first开始原数列与新数列不同的数据位置是PX,并且新数据为X2。[PX+1,last)总是递减的,[first,PX)没有改变,因为X2>X1,所以不管X2后面怎样排列都比原数列大,反转[PX+1,last)使此子数列(递增)为最小。从而保证的新数列为原数列的字典序排列next。
由此看来,next_permutation在工作时效率还是挺高的,只是一般排列总数会比较多,所以用next_permutation遍历会超时。
然后就考虑dfs,可以说这题才让我彻底明白了剪枝的重要和体会到了一些技巧:
1、从maxx到all遍历length,(oj上的std里面好像存在max,用max会存在冲突)
2、只遍历all的约数。
3、如果开始测试一个新木棍时,最长的那根木棍不能被使用的话,就返回0,因为在接下来的遍历中,更不可能用到这根长木棍。(这一点还是看得别人的题解。。。我开始没想到这个优化会是这么重要)
数据量较大时3很重要
代码只在poj上通过了。。。继续努力吧,回溯的内容比我想得要丰富
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,stick[60],all,maxx,length,amount;
int input[1000][60],temp[1000],in=0;
int dfs(int which,int l,int ceil,int one)
{
//printf(" %d %d %d %d\n",which,l,length,ceil);
int i,j,flag=0;
if(l==length)
{
which++;
if(which==ceil)
return 1;
else
{
for(i=1;i<=50;i++)
{
if(stick[i]>0)
{
stick[i]--;
if(dfs(0,i,1,0)==0)
{
stick[i]++;
//printf("a");
return 0;
}
stick[i]++;
}
}
return dfs(which,0,ceil,0);
}
}
for(i=50;i>0;i--)//递减会快很多
{
if(stick[i]>0)
{
flag++;
if(l+i<=length)
{
stick[i]--;
if(dfs(which,l+i,ceil,one+1))
{
stick[i]++;
return 1;
}
else
{
stick[i]++;
if(one==0&&flag==1)
return 0;
}
}
}
}
return 0;
}
int main()
{
//printf("%d",lcm(12,1000));
int i,j,a,help;
while(scanf("%d",&n)&&n)
{
all=maxx=0;
memset(stick,0,240);
while(n--)
{
scanf("%d",&a);
all+=a;
if(a>maxx)
maxx=a;
stick[a]++;
}
for(length=maxx;length<=all;length++)
{
if(all%length!=0)
continue;
for(i=1;i<=50;i++)
{
if(stick[i]>0)
{
stick[i]--;
if(dfs(0,i,1,0)==0)
{
stick[i]++;
//printf("b");
goto next;
}
stick[i]++;
}
}
//printf("%d %d\n",all,length);
/*for(i=1;i<=50;i++)//这一步优化存在问题,当每个元素都一样时会continue掉
if(stick[i]!=0)
break;
if(i+maxx>length)
continue;*/
if(dfs(0,0,all/length,0))
{
printf("%d\n",length);
break;
}
next:;
}
}
return 0;
}