题解0007:小木棍(P1120)

题解0007:小木棍(P1120)_第1张图片

 

 (错误记录)

题目链接:https://www.luogu.com.cn/problem/P1120

题目描述:几根同样长的木棍,小冥把它们随意砍成了n段;

     然后他又吃饱了撑的想把木棍拼上;

     但是这个小冥是小年痴呆,他忘了他原来是咋切的了;

     现在要写一段程序,输入n和切断的每段木棍的长,输出原始木棍的最小可能长度。

题目思路:搜索剪枝,这道题搜索其实很好说,直接从小到大枚举长度,然后递归判断可行性;

     难点还是在剪枝上,如果不用剪枝的话只能得9分左右,这道题要用到7个剪枝;

     具体的详见代码;

代码:

#include
using namespace std; int n,arr[66]={0},ans,brr[66]={0},we,wer;//arr存木棍长度,brr存木棍是否被用过 bool cmp(int a,int b){//将所有木棍从大到小排序 return a>b; } bool dfs(int a,int b,int c){//a是假定小木棍的剩余长度,b是循环初始值,c是木棍根数 if(c==wer){//木棍根数对上了 return 1; } if(a==0){//一根木棍拼完 if(dfs(we,1,c+1)){//根数+1 return 1; } } for(int i=b;i<=n;++i){ //剪枝3:下次循环的初始值完全可以接上上次循环的结束值 if(arr[i]<=a&&brr[i]!=1){//木棍没被用过&&长度没超 brr[i]=1;//标记 if(dfs(a-arr[i],i+1,c)){//-去长度 return 1; } brr[i]=0;//回溯 if(a==arr[i]||a==we){ //剪枝4:如果这个木棍长度与剩余长度一样,这已经是最优解了,还不行,那直接返 //剪枝5:如果剩余长度与假定木棍长度一样,和剪枝4一样,直接返 return 0;//如果写break可能过不了 } while(arr[i+1]==arr[i]){ //剪枝6:因为排了序,所以有很多相等的数在一起,遇到相等的数直接跳 i++; } } } return 0; } int main(){ cin>>n; for(int i=1;i<=n;++i){ cin>>arr[i]; ans+=arr[i]; } sort(arr+1,arr+n+1,cmp); for(int i=arr[1];i<=ans/2;++i){//这个数从最小木棍长度开始枚举 //剪枝1:如果枚举到所有木棍长度+起来/2还没有找到,那结果就一定是所有数加起来了,往下搜没意义了 if(ans%i==0){ //剪枝2:只有能被总长度整除的数才有可能是结果,不满足条件的直接扔掉 we=i; wer=ans/we; if(dfs(we,1,0)){//递归判断可行性 cout<return 0;//可以直接结束 } } } cout<return 0; }

你可能感兴趣的:(题解0007:小木棍(P1120))