标签:def sizeof 题解 失败 i++ include help The main
Input
Output
Sample Input
9 5 2 1 5 2 1 5 2 1 4 1 2 3 4 0
Sample Output
6 5
题意
给出一定数量的小木棒的长度,它是由等长的若干木棒随意砍断所得到的。对于给定的一组小木棒,请求出原始木棒的最小长度。
题解
dfs搜索,
思想很简单,一个接一个的把木棍拼起来,最后把木棍用光。关键的地方是几个剪枝技巧:设所有木棍的总长度为 Sum, 最终的答案(长度)是 L。 1. 首先要明白, Sum一定要能被 L 整除。 2. L 一定 大于等于 题目给出的最长的木棍的长度 Max。由上述两点,我们想到,可以从 Max 开始递增地枚举 L, 直到成功地拼出 Sum/L 支长度为 L 的木棍。
搜索中的剪枝技巧: 3. 将输入的输入从大到小排序,这么做是因为一支长度为 K 的完整木棍,总比几支短的小木棍拼成的要好。形象一些:如果我要拼 2 支长为8的木棍,第一支木棍我拼成 5 + 3 然后拼第二支木棍但是失败了,而我手中还有长为 2 和 1 的木棍,我可以用 5 + 2 + 1 拼好第一支,再尝试拼第二支,仔细想一想,就会发现这样做没意义,注定要失败的。我们应该留下 2+1 因为 2+1 比 3 更灵活。 4. 相同长度的木棍不要搜索多次, 比如:我手中有一些木棍, 其中有 2 根长为 4 的木棍, 当前搜索状态是 5+4+.... (即表示长度为 5,4,2 的三支拼在一起, ...表示深层的即将搜索的部分), 进行深搜后不成功,故我没必要用另一个 4 在进行 5+4+...5. 将开始搜索一支长为 L 的木棍时,我们总是以当前最长的未被使用的 木棍开始,如果搜索不成功,那么以比它短的开始那么也一定不能取得全局的成功。因为每一支题目给出的木棍都要被用到。如果,有4 5 4 4 3 2想拼成长为 6 的木棍,那么从 5 开始, 但是显然没有能与 5一起拼成 6 的,那么我就没必要去尝试从 4 开始的,因为最终 5 一定会被遗弃。在拼第 2 3 ... 支木棍时,一样。
#include<iostream> #include<algorithm> #include<cstring> #include<sstream> #include<cmath> #include<cstdlib> #include<queue> using namespace std; #define PI 3.14159265358979323846264338327950 int len[66]; bool vis[66]; int sum,l,n; int cmp(const void *a,const void *b) { return *(int *)b-*(int *)a; } bool dfs(int m,int left) { if(m==0 && left==0) return true; if(left==0) left=l; for(int i=0;i<n;++i) { if(!vis[i] && len[i]<=left) { if(i>0) { if(!vis[i-1] && len[i]==len[i-1]) continue; } vis[i]=true; if(dfs(m-1,left-len[i])) return true; else { vis[i]=false; if(left==len[i]||left==l) //重要剪枝,不佳这句会超时 return false; } } } return false; } int main() { while(scanf("%d",&n) && n) { sum=0; for(int i=0;i<n;i++) { scanf("%d",&len[i]); sum=sum+len[i]; } qsort(len,n,sizeof(int),cmp); for(l=len[0];l<=sum/2;++l) { if(sum % l) continue; memset(vis,false,sizeof(vis)); if(dfs(n,l)) { printf("%d\n",l); break; } } if(l>sum/2) printf("%d\n",sum); } }
标签:def sizeof 题解 失败 i++ include help The main
原文地址:https://www.cnblogs.com/smallhester/p/9498831.html