题目
题意
将n节木棒接成m个长度相等的木条,要求木条的长度尽可能的短。
思路
DFS没什么好说的了,说一下几个剪枝的地方。
<1>首先,拼成木条的长度必须是所有木棒长度总和的约数,并且大于等于木条中的最大值。
<2>将木棒从打到小排列,可以减少递归的层数。
<3>当第i个木棒未选取时,如果i+ 1木棒与i木棒相同长度。跳过, 没有必要重复考虑。
<4>当遍历到i个木棒时,找不到小木棒和它组成木条时, 可以终止当前判断的木条长度。
代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+5;
const int inf=0x3f3f3f3f;
typedef long long ll;
int stick[maxn];
bool vis[maxn];
int n;
int ans,sum;
bool cmp(int a,int b)
{
return a>b;
}
bool dfs(int cnt,int pos,int sum)//cnt表示已经用了几个木棒,pos表示最新一个用到的木棒的位置,sum表示这些木棒加起来的长度
{
if(cnt==n)
return true;
for(int i=pos;i<n;i++)
{
if(vis[i])
continue;
if(sum+stick[i]<ans)
{
vis[i]=true;
if(dfs(cnt+1,i+1,sum+stick[i]))
return true;
vis[i]=false;
while(stick[i]==stick[i+1]&&i+1<n)
{
i++;
}
}
else if(sum+stick[i]==ans)
{
vis[i]=true;
if(dfs(cnt+1,0,0))
return true;
vis[i]=false;
return false;
}
if(sum==0)
return false;
}
return false;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
while(cin>>n&&n)
{
ans=0;
sum=0;
memset(stick,0,sizeof(stick));
for(int i=0;i<n;i++)
{
cin>>stick[i];
sum+=stick[i];
}
sort(stick,stick+n,cmp);
for(int i=n;i>0;i--)
{
if(sum%i==0&&(sum/i)>=stick[0])
{
ans=sum/i;
memset(vis,false,sizeof(vis));
if(dfs(0,0,0))
{
cout<<ans<<endl;
break;
}
}
}
}
}