POJ 1011 (DFS+剪枝)
题目意思给你n个数,大于50的不算。让你把这n个数分成m组,每组的长度相同为len,使得这个len最短
光用dfs写会超时,剪枝要剪很多方面
1:优化搜索顺序 把木棍从大到小排序,优先尝试长的木棍
2:排除等效冗余
1.当上一个搜索失败了,下一个的数若等于上一个失败的数,那么一定失败
2.如果在当前木棒中尝试拼第一根木棍的递归分支就失败,那么直接判断当前分支失败,立即回溯
3.限制先后加入一
#include <iostream> #include <cmath> #include <cstdio> #include <cstring> #include <string> #include <map> #include <iomanip> #include <algorithm> #include <queue> #include <stack> #include <set> #include <vector> //const int maxn = 1e5+5; #define ll long long ll gcd(ll a,ll b){return b?gcd(b,a%b):a;} ll lcm(ll a,ll b){return a/gcd(a,b)*b;} #define MAX INT_MAX #define FOR(i,a,b) for( int i = a;i <= b;++i) #define bug cout<<"--------------"<<endl using namespace std; bool cmp(int a,int b) { return a>b; } int cnt,sum,maxx,len,n; int vis[500],a[500]; int dfs(int k,int cab,int last)// last排除等效冗余3 { if(k > cnt) { return true; } if(cab==len) { return dfs(k+1, 0 ,1); } int fail=0; // 排除等效冗余1 for(int i=last;i<=n;++i) // last排除等效冗余3 { if(vis[i]==0 && cab+a[i]<=len &&fail!=a[i]) { vis[i]=1; if(dfs(k,cab+a[i],i+1)) return true; fail=a[i]; vis[i]=0; if (cab==0 || cab+a[i]==len)//如果cab为0,或者相加正好是len,但是失败了,那么一定是失败了.//排除等效冗余2 return false; } } return false; } int main() { ios::sync_with_stdio(false); // freopen("D:\\common_text\\code_stream\\in.txt","r",stdin); // freopen("D:\\common_text\\code_stream\\out.txt","w",stdout); while(cin>>n && n) { int x=0,hhh=0; memset(vis,0,sizeof(vis)); sum=0; maxx=0; cnt=0,len; FOR(i,1,n) { cin>>x; if(x<=50) { hhh++; } a[hhh]=x; sum+=x; maxx=max(maxx,x); } n=hhh; sort(a+1,a+1+n,cmp); for(int i=maxx;i<=sum;i++) //changdu { if(sum%i==0) { //cout<<i<<" "<<cnt<<" "<<endl; len=i; cnt=sum/i; memset(vis,0,sizeof(vis)); if(dfs(1,0,1)==1) break; } } cout<<len<<endl; } }
根原始木棒的长度是递减的(先加入x后加入y和先加入y后加入x是等效的,只需要搜索其中一种)