标签:dfs
转载请注明出处:http://blog.csdn.net/u012860063
题目链接:http://poj.org/problem?id=1011
Description
Input
Output
Sample Input
9 5 2 1 5 2 1 5 2 1 4 1 2 3 4 0
Sample Output
6 5
Source
题目的大意:是给了你有限个棍子以及每个棍子的长度,而且所有的棍子都是由有限个长度相同的棍子截断得到的,让你求被截棍子的最小长度,本题的算法是深搜,当然需要几个剪枝的!
代码如下:
#include <iostream> #include <algorithm> using namespace std; int sticks[65]; int used[65]; int n,len; bool dfs(int i,int l,int t)//i为当前试取的棍子序号,l为要拼成一根完整的棍子还需要的长度,t初值为所有棍子总长度 { if(l==0) { t -= len;//如果len为所有棍子的和 if(t == 0) return true; for(i = 0; used[i]; i++); //剪枝1:搜索下一根大棍子的时候,找到第一个还没有使用的小棍子开始 used[i]=1; //由于排序过,找到的第一根肯定最长,也肯定要使用,所以从下一根开始搜索 if(dfs(i+1,len-sticks[i],t)) return true; used[i]=0;//回溯 t+=len; } else { for(int j = i; j < n; j++) { if(j>0 && (sticks[j]==sticks[j-1]&&!used[j-1])) //剪枝2:前后两根长度相等时,如果前面那根没被使用,也就是由前面那根 continue; //开始搜索不到正确结果,那么再从这根开始也肯定搜索不出正确结果,此剪枝威力较大 if(!used[j] && l>=sticks[j]) //剪枝3:最简单的剪枝,要拼成一根大棍子还需要的长度L>=当前小棍子长度,才能选用 { l-=sticks[j]; used[j]=1; if(dfs(j,l,t)) return true; l+=sticks[j];//回溯 used[j]=0; if(sticks[j]==l) //剪枝4:威力巨大的剪枝,程序要运行到此处说明往下的搜索失败,若本次的小棍长度刚好填满剩下长度,但是后 break; //面的搜索失败,则应该返回上一层 } } } return false; } bool cmp(const int a, const int b) { return a>b; } int main() { while(cin>>n&&n) { int sum=0;int max = -1; for(int i = 0; i < n; i++) { cin>>sticks[i]; sum += sticks[i]; used[i] = 0; if(sticks[i] > max)//找出最长的棍子 max = sticks[i]; } sort(sticks,sticks+n,cmp); //剪枝5:从大到小排序后可大大减少递归次数 bool flag=false; for(len = max; len <= sum/2; len++) //剪枝6:大棍长度一定是所有小棍长度之和的因数,且最小因数应该不小于小棍中最长的长度 { if(sum%len == 0) { if(dfs(0,len,sum)) { flag=true; cout<<len<<endl; break; } } } if(!flag) cout<<sum<<endl; } return 0; }
poj1011 Sticks DFS+回溯,布布扣,bubuko.com
标签:dfs
原文地址:http://blog.csdn.net/u012860063/article/details/34948659