3.搜索、模拟
搜索、模拟
开题顺序: \(HGA\)
\(A\) luogu P1120 小木棍
-
把能想到的剪枝加上。
- 最终答案一定是 \(\sum\limits_{i=1}^{n}a_{i}\) 的因数。
- 优化搜索顺序,将 \(\{ a \}\) 先降序排序,同时先选择长度尽可能长的进行拼接。
- 猜测 \(\{ a \}\) 中会有许多重复元素,开桶或者记录上一个递归失败的匹配状态。
- 钦定匹配顺序是递减的,减少冗余状态的搜索。
- 剩余木棍中尝试拼接的第一根木棍递归就失败,则直接返回失败。
- 拼接完一根木棍后恰好被拼接完整且接下来的递归失败,则直接返回失败。
点击查看代码
int a[70],vis[70]; bool dfs(int pos,int n,int len,int sum,int last) { if(pos==n+1) { return (sum==0); } else { int used=0; if(sum==0) { last=0; sum=len; } for(int i=last+1;i<=n;i++) { if(vis[i]==0&&sum-a[i]>=0&&a[i]!=used) { vis[i]=1; if(dfs(pos+1,n,len,sum-a[i],i)==true) { return true; } used=a[i]; vis[i]=0; if(sum==len||a[i]==sum) { break; } } } return false; } } int main() { int n,sum=0,i; cin>>n; for(i=1;i<=n;i++) { cin>>a[i]; sum+=a[i]; } sort(a+1,a+1+n,greater<int>()); for(i=a[1];i<=sum;i++) { if(sum%i==0&&dfs(1,n,i,i,0)==true) { cout<<i<<endl; break; } } return 0; }
\(B\) luogu P2540 [NOIP2015 提高组] 斗地主 加强版
\(C\) CF58E Expression
\(D\) CF293B Distinct Paths
- 当 \(n-m+1>k\) 时无解,故合法状态下的 \(n,m \le 10\) 。
\(E\) [ABC352F] Estimate Order
\(F\) [ABC336F] Rotation Puzzle
\(G\) CF525E Anya and Cubes
-
阶乘只需要处理到 \(18\) ,然后就是 meet in middle 板子了。
点击查看代码
ll a[30],jc[30],ans=0; unordered_map<ll,ll>f[30]; void dfs1(ll pos,ll n,ll m,ll k,ll sum,ll num) { if(pos==n+1) { f[num][sum]++; return; } else { dfs1(pos+1,n,m,k,sum,num); if(sum+a[pos]<=m) { dfs1(pos+1,n,m,k,sum+a[pos],num); } if(num+1<=k&&a[pos]<=18&&sum+jc[a[pos]]<=m) { dfs1(pos+1,n,m,k,sum+jc[a[pos]],num+1); } } } void dfs2(ll pos,ll n,ll m,ll k,ll sum,ll num) { if(pos==n+1) { for(ll i=0;i<=k-num;i++) { if(f[i].find(m-sum)!=f[i].end()) { ans+=f[i][m-sum]; } } return; } else { dfs2(pos+1,n,m,k,sum,num); if(sum+a[pos]<=m) { dfs2(pos+1,n,m,k,sum+a[pos],num); } if(num+1<=k&&a[pos]<=18&&sum+jc[a[pos]]<=m) { dfs2(pos+1,n,m,k,sum+jc[a[pos]],num+1); } } } int main() { ll n,k,m,i; cin>>n>>k>>m; for(i=1;i<=n;i++) { cin>>a[i]; } jc[0]=1; for(i=1;i<=18;i++) { jc[i]=jc[i-1]*i; } dfs1(1,n/2,m,k,0,0); dfs2(n/2+1,n,m,k,0,0); cout<<ans<<endl; return 0; }
\(H\) luogu P9234 [蓝桥杯 2023 省 A] 买瓜
-
为方便处理让 \(m'=2m\) ,然后就是超大背包板子了。
-
需要适当加上最优性剪枝和优化搜索顺序。
点击查看代码
ll a[50],ans=0x7f7f7f7f; unordered_map<ll,ll>f; void dfs1(ll pos,ll n,ll m,ll sum,ll num) { if(num>=ans) { return; } if(sum==m) { ans=min(ans,num); return; } if(pos==n+1) { if(f.find(sum)==f.end()) { f[sum]=num; } else { f[sum]=min(f[sum],num); } } else { dfs1(pos+1,n,m,sum,num); if(sum+a[pos]<=m) { dfs1(pos+1,n,m,sum+a[pos],num+1); } if(sum+2*a[pos]<=m) { dfs1(pos+1,n,m,sum+2*a[pos],num); } } } void dfs2(ll pos,ll n,ll m,ll sum,ll num) { if(num>=ans) { return; } if(sum==m) { ans=min(ans,num); return; } if(pos==n+1) { if(f.find(m-sum)!=f.end()) { ans=min(ans,f[m-sum]+num); } } else { dfs2(pos+1,n,m,sum,num); if(sum+a[pos]<=m) { dfs2(pos+1,n,m,sum+a[pos],num+1); } if(sum+2*a[pos]<=m) { dfs2(pos+1,n,m,sum+2*a[pos],num); } } } int main() { ll n,m,i; cin>>n>>m; m*=2; for(i=1;i<=n;i++) { cin>>a[i]; } sort(a+1,a+1+n); dfs1(1,n/2,m,0,0); dfs2(n/2+1,n,m,0,0); cout<<(ans==0x7f7f7f7f?-1:ans)<<endl; return 0; }
\(I\) POJ1475 Pushing Boxes
\(J\) UVA589 Pushing Boxes
本文来自博客园,作者:hzoi_Shadow,原文链接:https://www.cnblogs.com/The-Shadow-Dragon/p/18452305,未经允许严禁转载。
版权声明:本作品采用 「署名-非商业性使用-相同方式共享 4.0 国际」许可协议(CC BY-NC-SA 4.0) 进行许可。