标签:
题目的大致意思是:
现在有n根木棍,然后需要把它们拼成同样长度的木棍,问满足这个条件的最短的长度是多少?
想法嘛:那肯定是dfs把长度搜一遍就好,但问题的关键是这里会超时。那么就要用到剪枝的原理了。
以下部分是来自于pku的gw老师说哒
1)不要在同一个位置多次尝试相同长度的木棒(在某一次拼接时选择长度为s的木棒导致拼接失败,则在同一位置尝试下一根木棒时,要跳过所有长度为s的木棒)
2)如果由于以后的拼接失败,需要重新调整第i根棍子的拼法,则不会考虑替换第i根棍子中的第一根木棒。
3)不要希望通过仅仅替换已经拼好的棍子的最后一根木棒就能改变失败的局面。
4)拼每一根棍子的时候,应确保已经拼好的部分,长度是从长到短排列的(因为我们应该先拼长的,长的可能性小)
排除方法:每次找一根木棒的时候,只要这不是一根棍子的第一条木棒,那么不应该从下标为0的木棒开始找,而应该从刚刚接上去的那条木棒的下一条开始找(当然,我们要先对木棒进行从大到小的排序)
#include<stdio.h> #include<string.h> #include<iostream> #include<algorithm> #include<vector> #include<map> using namespace std; #define maxn 70 int a[maxn],n,L,vis[maxn],lastnum=0; bool cmp(int a,int b){ return a>b; } //当前还余下的棍子的个数和还缺的长度 bool dfs(int m,int l){ if(m==0&&l==0) return true; if(l==0) l=L; int s=1; //剪枝4 if(l!=L){ s=lastnum+1; } for(int i=s;i<=n;i++){ if(!vis[i-1]&&i>1&&a[i]==a[i-1]) continue; //剪枝1 if(!vis[i]&&a[i]<=l){ vis[i]=1; lastnum=i; if(dfs(m-1,l-a[i])) return true; else{ vis[i]=0; if(L==l||a[i]==l) return false; //剪枝2,3 } } } return false; } int main(){ while(~scanf("%d",&n)){ if(n==0) break; memset(a,0,sizeof(a)); int sum=0,lmax=-1; for(int i=1;i<=n;i++){ scanf("%d",&a[i]); if(a[i]>lmax) lmax=a[i]; sum+=a[i]; } int i=0; sort(a+1,a+1+n,cmp); #if 1 for(i=lmax;i<=sum/2;i++){ if(sum%i) continue; L=i; memset(vis,0,sizeof(vis)); lastnum=0; if(dfs(n,i)){ printf("%d\n",i); break; } } if(i>sum/2) printf("%d\n",sum); #endif } } /* 9 5 2 1 5 2 1 5 2 1 4 1 2 3 4 0 */
版权声明:本文为博主原创文章,未经博主允许不得转载。
标签:
原文地址:http://blog.csdn.net/acmer_hades/article/details/47069245