小木棒
这是我三个小时做出来的!不是因为难思考!是因为细节!!!哭了!
首先我们还是运用的是深搜的方法,里面我加上了二分法。
这个题的主要思路我觉得其实很简单
分析一下这道题目,我们不难发现,答案是有范围的,就是最小是最长那根小木棒,最大是所有小木棒之和!(划重点,敲黑板)
我们用一个next数组标记,如果有两根一样的木棒,两根的情况是一样的,所以我们算一个就好了。
每一次我们判定完一根木棒后,我们要把它标记,这样我们就不会重复计算了!
还有在输入的时候我们可以进行判定,因为题目中给出了,所以只要该根超过了50我们就可以直接把它拿出来了!
我们设一个函数(nume表示这个是第几根木棒;last是上一个木棒的编号;rest是这根大木棒还剩下多少要拼)
我们不难发现,其实从大到小排比从小到大简单,因为几根小的肯定会比一根大的灵活,我们这样思考这根问题就很简单的可以将这根木棒拼出来。
我们就先写个小代码,叫二分的小可爱:(就是这个小可爱不会让你的代码炸掉哦)
int l=last+1,r=coUnt,mid;
while(l<r)
{
mid=(l+r)/2;
if(a[mid]<=rest)
{
r=mid;
}
else
{
l=mid+1;
}
}
然后我们判定一下这个小木棒的组成,m代表的是我们这种情况分出的大木棒根数,裁枝:如果等于我们假设的了,我们就可以停止了。 下面就是我的代码了:
#include<bits/stdc++.h>
using namespace std;
int a[70] ;
int n , m , sum , next[70],len,coUnt;
bool gg[70],pass;
bool comp (int a,int b){return a>b;}
void jj(int num , int last , int rest)
{
int i;
int l=last+1,r=coUnt,mid;
while(l<r)
{
mid=(l+r)/2;
if(a[mid]<=rest)
{
r=mid;
}
else
{
l=mid+1;
}
}
if(!rest)
{
if(num==m)
{
pass=1;
return ;
}
for(i=1;i<=coUnt;i++)
{
if(!gg[i]) break;
}
gg[i]=1;
jj(num+1,i,len-a[i]);
gg[i]=0;
if(pass)
{
return;
}
}
for(i=l;i<=coUnt;i++)
{
if(!gg[i])
{
gg[i]=1;
jj(num,i,rest-a[i]);
gg[i]=0;
if(pass)
return ;
if(rest==a[i]||rest==len)
return ;
i=next[i];
if(i==coUnt)
return ;
}
}
}
int main()
{
int llo;
scanf("%d", &n );
for(int i = 1 ; i <= n ; i++)
{
scanf("%d",&llo);
if(llo>50) continue;
a[++coUnt]=llo;
sum+=llo;
}
sort(a+1,a+coUnt+1,comp);
next[coUnt]=coUnt;
for(int i=coUnt-1;i>0;i--)
{
if(a[i]!=a[i+1])
next[i]=i;
else
next[i]=next[i+1];
}
for(len=a[1];len<=sum/2;len++)
{
if(sum%len!=0)
continue;
pass=0;
gg[1]=1;
m=sum/len;
jj(1,1,len-a[1]);
gg[1]=0;
if(pass)
{
printf("%d\n",len);
return 0;
}
}
printf("%d\n",sum);
return 0;
}