搜索树
剪枝方法
1.优化搜索顺序
2.排除等效冗余
3.可行性
4.最优性(估价)
5.记忆化(树形不会重复计算时不需要)
A.针对每个维度边界信息缩放、推倒
B.计算未来最少花费
C.结合各维度的联系
P1120 小木棍
https://www.luogu.org/problemnew/show/P1120
bool dfs(int p,int u,int x) { if(p>cnt) return 1; if(u==len) return dfs(p+1,0,1); int lf=0; FOR(i,x,n) if((!vis[i])&&a[i]+u<=len&&a[i]!=lf)//剪枝2 { vis[i]=1; if(dfs(p,a[i]+u,i+1)) return 1; vis[i]=0;lf=a[i]; if(u+a[i]==len||u==0) return 0;//剪枝3.4 } return 0; } int main() { //freopen("hh.in","r",stdin); nnn=rd(); FOR(i,1,nnn) { int tptp=rd(); if(tptp>50) continue; a[++n]=tptp,cc+=a[n],gmax(mx,a[n]); } sort(a+1,a+n+1,greater<int>() ); //FOR(i,1,n) cout<<a[i]<<" ";cout<<endl; for(len=mx;len<=cc;++len) { if(cc%len) continue; cnt=cc/len; memset(vis,0,sizeof(vis)); if(dfs(1,0,1)){cout<<len;break;} } return 0; }
P1731 [NOI1999]生日蛋糕
https://www.luogu.org/problemnew/show/P1731
#include<iostream> #include<cstdio> #include<cmath> using namespace std; #define FOR(i,a,b) for(register int i(a);i<=b;++i) #define For(i,a,b) for(register int i(a);i>=b;--i) int mins[20],minv[20]; int ans=1<<30,s; bool prune(int maxh,int maxr,int n,int v) { int cc=0; FOR(i,0,n-1) cc+=(maxh-i)*(maxr-i)*(maxr-i); if(cc<v) return 1; else return 0; } void dfs(int maxh,int maxr,int n,int v,int m) { if(n==0) { if(v) return; ans=min(ans,s); } if(s+mins[n]>ans) return; if(maxh<n||maxr<n) return; if(minv[n]>v) return; if(prune(maxh,maxr,n,v)) return; For(i,maxr,n) { if(n==m) s=i*i; For(j,maxh,n) { s+=2*i*j; dfs(j-1,i-1,n-1,v-i*i*j,m); s-=2*i*j; } } } int main() { int n,m;scanf("%d%d",&n,&m); FOR(i,1,m) mins[i]=mins[i-1]+2*i*i, minv[i]=minv[i-1]+i*i*i; if(n<minv[m]) printf("0"); else { int maxh=(n-minv[m-1])/(m*m)+1; int maxr=sqrt((n-minv[m-1])/m)+1; dfs(maxh,maxr,m,n,m); if(ans==1<<30) printf("0"); else printf("%d",ans); } return 0; }
迭代加深
a.搜索树规模增长快
b.从小到大限制深度
双向搜索
“终态”明确,路径可逆
CH2401 送礼物
先从前(N/2+2)中选若干个,存放,排序,去重
再枚举后一半,二分查找对应的前一半的值
1 void dfs1(int i, unsigned int sum) { 2 if (i == half) { 3 a[++m] = sum; 4 return; 5 } 6 dfs1(i + 1, sum); 7 if (sum + g[i] <= w) dfs1(i + 1, sum + g[i]); 8 } 9 10 void calc(unsigned int val) { 11 int rest = w - val; 12 int l = 1, r = m; 13 while (l < r) { 14 int mid = (l + r + 1) / 2; 15 if (a[mid] <= rest) l = mid; else r = mid - 1; 16 } 17 ans = max(ans, a[l] + val); 18 } 19 20 void dfs2(int i, unsigned int sum) { 21 if (i == n + 1) { 22 calc(sum); 23 return; 24 } 25 dfs2(i + 1, sum); 26 if (sum + g[i] <= w) dfs2(i + 1, sum + g[i]); 27 } 28 29 int main() { 30 cin >> w >> n; 31 for (int i = 1; i <= n; i++) scanf("%d", &g[i]); 32 sort(g + 1, g + n + 1); 33 reverse(g + 1, g + n + 1); 34 half = n / 2 + 3; 35 dfs1(1, 0); 36 sort(a + 1, a + m + 1); 37 m = unique(a + 1, a + m + 1) - (a + 1); 38 dfs2(half, 0); 39 cout << ans << endl; 40 }
IDA*
估价函数+迭代加深
若当前深度+未来估价>深度限制,立即回溯