http://acm.hdu.edu.cn/showproblem.php?pid=1455
分析:与hdu 1518类似:http://blog.csdn.net/killua_99/article/details/9569709
但明显多了各种剪枝,主要是对题目分析,明白:这些木棒都由相同长度得来,1)可能原长度一定是总和的约数,2)最小可能是从最大的木棒开始计算 etc
测试数据:http://poj.org/showmessage?message_id=172549
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int NM=70;
int vis[NM],a[NM];
int c,flag,n;
bool comp(int A,int B)
{
if(A>B) return 1;
else return 0;
}
void DFS(int stick,int ssum,int ans,int k)
{
if(ans==stick)
{
ssum++;
ans=k=0; //注意把k也更新了
if(ssum==c)
flag=1;
}
if(flag) return;
for(int i=k;i<n;i++)
{
if(!vis[i]&&stick>=ans+a[i])
{
ans+=a[i];
vis[i]=1;
DFS(stick,ssum,ans,i+1);
ans-=a[i];
vis[i]=0;
if(k==0||flag) return; /*最重要的剪枝:如果第一根木棒不能形成组合,那么这组数一定不成立*/
while(a[i+1]==a[i]) i++; //防止重复搜索
}
}
}
int main()
{
int sum,i;
//freopen("out.txt","w",stdout);//文件
while(cin>>n&&n)
{
sum=0;
for(i=0;i<n;i++)
{
scanf("%d",&a[i]);
sum+=a[i];
}
if(n==1) //
{
printf("%d\n",sum);
continue;
}
sort(a,a+n,comp); //从较长的木棒开始搜索(因为可能几个较小木棒结合成功,本来它们分别要与较大木棒结合),可以减少回溯次数
for(i=a[0];i<=sum;i++) //好像存在不砍木棒的情况
{
if(sum%i!=0) continue;
memset(vis,0,sizeof(vis));
c=sum/i; //木棒原先个数
flag=0;
DFS(i,0,0,0); //木棒原先长度;个数,长度,第几只木棒
if(flag)
{
printf("%d\n",i);
break;
}
}
}
return 0;
}
再次尝试:
不排序与排序的效率比较:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int NM=70;
int a[NM],n,temp,num;
bool vis[NM],flag;
void DFS(int ans,int k,int res)
{
if(flag) return;
if(res==temp){
ans++;
res=k=0;
}
if(ans==num){
flag=true;
return;
}
for(int i=k;i<n;i++){
if(!vis[i] && res+a[i]<=temp){
vis[i]=1;
DFS(ans,i+1,res+a[i]);
vis[i]=0;
if(k==0 || flag) return;
while(a[i+1]==a[i]) i++;
}
}
}
int main()
{
int mmax,i,sum;
while(scanf("%d",&n)&&n)
{
sum=mmax=0;
for(i=0;i<n;i++)
{
scanf("%d",&a[i]);
sum+=a[i];
if(mmax<a[i]) mmax=a[i];
}
flag=false;
for(i=mmax;i<=sum;i++)
{
if(sum%i==0){
num=sum/i;temp=i;
memset(vis,0,sizeof(vis));
DFS(0,0,0);
if(flag){
printf("%d\n",i);
break;
}
}
}
}
return 0;
}