刚开始在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/