刚开始在poj过了,拿到uva居然超时。改了好久都没成功,最后问了一个同学,稍微改了一下思路才ac。给uva数据跪了,电费不要钱吗?
这题数据太恶心,所以必需剪枝。
1.将数据从大到小排序,方便后面选择和操作。
2.最后答案只能是sum的约数,所以枚举范围最小为最长的那个棍子的长度,最大只需要到sum/2,如果前面没有求出答案,那么就是sum了。
3.在深搜过程中,如果当前棍子没有用上,下一个棍子如果长度一样,不用再试。
4.各种异常情况返回。
#include "stdio.h"
#include "string.h"
#include "algorithm"
using namespace std;
int a[70],u[70],ans,n,s;
bool flag;
bool cmp(int x,int y)
{
return x>y;
}
void dfs(int num,int st,int len)
{
int i;
if(num==s) {flag=1;return;}
if(flag) return;
for(i=st;i<n;i++)
{
if(!u[i])
{
u[i]=1;
if(a[i]+len<ans) dfs(num,i+1,a[i]+len);
else if(a[i]+len==ans) dfs(num+1,0,0);
u[i]=0;//恢复现场
if(!st||a[i]==ans||a[i]+len==ans) return;//4对各种可以继续搜索下去的,却反回了的剪枝。没有这一步会超时
while(a[i+1]==a[i]) i++;//3中剪枝
}
}
return ;
}
int main()
{
int i,sum;
while(~scanf("%d",&n))
{
if(n==0) break;
sum=0,flag=0;
for(i=0; i<n; i++)
{
scanf("%d",&a[i]);
sum+=a[i];
}
sort(a,a+n,cmp);//从大到小排序
for(ans=a[0];ans<=sum/2; ans++)
{
if(sum%ans==0)
{
s=sum/ans;
memset(u,0,sizeof(u));
dfs(0,0,0);
if(flag==1) break;
}
}
if(ans>sum/2) printf("%d
",sum);
else printf("%d
",ans);
}
return 0;
}
#include "stdio.h"
#include "string.h"
#include "algorithm"
using namespace std;
int a[70],u[70],ans,n;
bool cmp(int x,int y)//sort排序用的
{
return x>y;
}
bool dfs(int num,int len,int st)
{
if(num==n) return 1;//全部的棒子都实用了
else if(len==ans) return dfs(num,0,0);
else
{
int i,t;//t记录ai-1,剪枝,如果相等的棒子第一个没用,后面也不去用
for(t=0,i=st;i<n;i++)
if(!u[i]&&len+a[i]<=ans&&t!=a[i])//可以使用
{
t=a[i],u[i]=1;
if(dfs(num+1,len+a[i],i+1)) break;
u[i]=0;//恢复现场
if(st==0) return 0;//如果遍历了一遍后,为找到ai,当前ans错误,返回
}
if(n==i) return 0;//如果遍历了一遍后,为找到ai,当前ans错误,返回
else return 1;
}
}
int main()
{
int i,sum;
while(~scanf("%d",&n))
{
if(n==0) break;
sum=0;
for(i=0; i<n; i++)
{
scanf("%d",&a[i]);
sum+=a[i];
}
sort(a,a+n,cmp);//从大到小排序
//从最长的棒子开始遍历,最大为sum
for(ans=a[0]; ans<sum; ans++)
{
if(sum%ans==0)//ans肯定能被sum整除
{
memset(u,0,sizeof(u));//数组清零,0为未用,1为已用
if(dfs(0,0,0))
break;
}
}
printf("%d
",ans);
}
return 0;
}版权声明:本文为博主原创文章,未经博主允许不得转载。http://xiang578.top/