P3067 Balanced Cow Subsets G
折半搜索好题
P3067 Balanced Cow Subsets G
思路:
1. 分析:
首先,由数据范围可以判断出,一定是搜索。
并且 告诉我们还可以用状压来记录状态。
然后注意,题目的要求是对于求有多少“平衡”的子集,所以我们可以有三种思路:
- 枚举每个集合,判断是否可以拆分。
- 枚举某个集合,判断是否有另一个集合可以拼在一起组合出一个答案。
- 整体枚举,对于每一个奶牛将其分入 , 或不选。
显然,第一个无法快速的判断,第二个无法快速去重,第三个复杂度是 无法接受。
但是对于前两个,显然不像可做的样子,考虑转化第三个。
2. 转化:
对于暴搜一类的算法的优化,要么是剪枝,要么是折半搜索。
而对于求方案数量的题目,一般不能剪枝,所以考虑折半搜索。
但是折半搜索要求搜索的内容必须独立,不会相互影响,还要求对于前后搜索出来的结果要可以快速合并,现在分为 、
两组显然不符合。
还要转化:
对于 一类的东西,有一个转化的通法:
即在求分组之后相等的时候,可以转化为相减为 ,方便求解。
就是可以对于需要分组的数分配权值、或,直接累加,就代表“选”“不选”“放在另一组”,求的就是最后的累加和为 。
这样,我们就可以将每个物品独立出来,变成了每个物品有独立的 种状态,最后要求前后的累加和为 。
所以直接折半搜索,之后通过状压来去重。
Code:
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int rt=0; char g=getchar();
while(g<'0'||g>'9') g=getchar();
while(g>='0'&&g<='9') rt=(rt<<3)+(rt<<1)+g-'0',g=getchar();
return rt;
}
int n,m,up,ans;
int a[25],ck[(1<<20)];
int cnt;
map<int,int>mp;
vector<int>v[(1<<20)];
inline void dfs1(int now,int sum,int w)
{
if(now>up)
{
if(!mp.count(sum)) mp[sum]=++cnt;
v[mp[sum]].push_back(w);
return;
}
dfs1(now+1,sum,w);
dfs1(now+1,sum-a[now],w|(1<<(now-1)));
dfs1(now+1,sum+a[now],w|(1<<(now-1)));
}
inline void dfs2(int now,int sum,int w)
{
if(now>up)
{
int opt=mp[-sum];
for(int i=0;i<v[opt].size();i++) ck[w|v[opt][i]]=1;
return;
}
dfs2(now+1,sum,w);
dfs2(now+1,sum-a[now],w|(1<<(now-1)));
dfs2(now+1,sum+a[now],w|(1<<(now-1)));
}
int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
n=read();
for(int i=1;i<=n;i++) a[i]=read();
if(n==1){putchar('0');return 0;}
up=(n>>1); dfs1(1,0,0);
up=n; dfs2((n>>1)+1,0,0);
for(int i=1;i<(1<<n);i++) ans+=ck[i];
printf("%d",ans);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话