题目地址:点击打开链接
题意:小明拿来几根相同长度的棍子,然后把这些棍子截成好几节,问最后能拼成几根长度相同的棍子(要求这些棍子的长度最小)
思路:和HDU1518相似,可以看本博客,那道题解写的比较详细,这不过这道题得在那道题上多加几个减枝才能A
AC代码:
#include <iostream> #include <cstdio> #include <cstdlib> #include <algorithm> #include <queue> #include <stack> #include <map> #include <cstring> #include <climits> #include <cmath> #include <cctype> using namespace std; int a[70]; bool flag; int n,l; int length; int visit[70]; void dfs(int start,int sum,int now) { int i; if(flag) return; if(sum == l) { flag = true; return; } for(i=start; i<n; i++) { if(!visit[i]) { if(now + a[i] == length) { visit[i] = 1; dfs(0,sum+1,0); visit[i] = 0; } else if(now + a[i] < length) { visit[i] = 1; dfs(i+1,sum,now+a[i]); visit[i] = 0; if(now == 0)//减枝1 return; while(a[i] == a[i+1])//减枝2,相同长度的就不用再搜了 i++; } } } } int main() { int i; while(scanf("%d",&n) && n) { flag = false; int sum = 0; for(i=0; i<n; i++) { scanf("%d",&a[i]); sum += a[i]; } sort(a,a+n); for(i=a[n-1]; i<=sum; i++)//最后组成的边肯定大于等于最长边,枚举边比较好,枚举条数不好,原因看超时代码下面的解释 { if(sum % i == 0) { memset(visit,0,sizeof(visit)); l = sum / i; length = i; dfs(0,0,0); if(flag) { printf("%d\n",i); break; } } } } return 0; }
超时代码:
#include <iostream> #include <cstdio> #include <cstdlib> #include <algorithm> #include <queue> #include <stack> #include <map> #include <cstring> #include <climits> #include <cmath> #include <cctype> using namespace std; int a[70]; bool flag; int n,l; int length; int visit[70]; void dfs(int start,int sum,int now) { int i; if(flag) return; if(sum == l) { flag = true; return; } for(i=start; i<n; i++) { if(!visit[i]) { visit[i] = 1; if(now + a[i] == length) { dfs(0,sum+1,0); } else if(now + a[i] < length) { dfs(i+1,sum,now+a[i]); } visit[i] = 0; } } } int main() { int i,j; while(scanf("%d",&n) && n) { flag = false; int sum = 0; int min1 = 1000000000; for(i=0; i<n; i++) { scanf("%d",&a[i]); sum += a[i]; if(a[i] < min1) min1 = a[i]; } sort(a,a+n); for(i=sum; i>=min1; i--) { if(sum % i == 0) { memset(visit,0,sizeof(visit)); l = i; length = sum / i; for(j=0; j<n; j++) { if(a[j] > length) break; } if(j == n) { dfs(0,0,0); if(flag) { printf("%d\n",length); break; } } } } } return 0; }
其实我这个代码写的还是比较逗的,最小值排序一下就能出来,我却特意求了一下,然后枚举的条数,结果里面多加了一个for循环减枝,并且for循环的范围大,枚举边的范围是从最大边到sum,而枚举条数是从最小边到sum,这样不就是把时间搞的更长了么