题意:
有好多根短棍
他们可以组合成n个长度相同的长棍
求长棍的最短值
粗略参考了网上的1个剪枝技巧:排序,舍弃 之前相同长却搜失败的棍子
然后开始自己编写
发现速度超时, 对着数字推演半天,最终发现len=0,也就是搜新棍子,但是往下搜却失败,那么这根棍子将不存在,这是不可能的,所以直接要直接跳回上级
明天开始回顾图论,看看华为的那个参赛题到底难不难
#include<stdio.h>
#include<string.h>
#include<math.h>
#define M 2000
int flag[M],stick[M];
int stick_n,want_len,ans_flag,bad_flag;
void dfs(int n,int len)
{
int i,change_flag=1;
if(ans_flag==1) //如果已经发现答案,则退出
return ;
if(len>want_len) //如果len比假设棍长 大,则退出
return ;
if(len==want_len) //如果等于假设棍长,则看n
{
if(n==stick_n) //相等,说明找到答案
{
ans_flag=1;
}
else
len=0; //否则,说明已经找到一组假设棍长组合,len重置0.往下继续找
}
for(i=0;i<stick_n&&ans_flag!=1&&bad_flag!=1;i++)
{
if(i!=0&&stick[i]==stick[i-1]) //如果之前与自己相同的棍子往下搜时都没找到,则跳过
{
if(change_flag==0)
continue;
}
else change_flag=1;
if(flag[i]==1) //如果棍子已被选择过,则跳过
continue;
flag[i]=1;//选择此棍
dfs(n+1,len+stick[i]); //往下搜
change_flag=0; //说明这个棍子没找到,那么与他相同的棍子往下搜肯定也失败
flag[i]=0; //取消此棍选择
if(len==0) //如果这个棍子是新棍的第一个,dfs失败,那么后面此棍将不存在,这样不合理
//故跳过之后所有棍子的搜索
{
break;
}
}
}
void sort()
{
int i,j,temp;
for(i=0;i<stick_n;i++)
for(j=i;j<stick_n;j++)
{
if(stick[i]<stick[j])
{
temp=stick[i];
stick[i]=stick[j];
stick[j]=temp;
}
}
}
void main()
{
int sum,i,max;
while(scanf("%d",&stick_n),stick_n!=0)
{
sum=0;
for(i=0;i<stick_n;i++)
{
scanf("%d",&stick[i]);
sum+=stick[i];
flag[i]=0;
}
sort(); //排序,从大到小
max=stick[0]; //原棍长应该在max到sum之间
ans_flag=0;
for(i=max;i<=sum;i++)
{
if(sum%i!=0) //如果假设原棍长不被sum整除,则舍弃
continue;
want_len=i; //假设原棍长
dfs(0,0);
if(ans_flag==1) //发现答案,则输出
{
printf("%d\n",i);
break;
}
}
}
}