随笔 - 188  文章 - 0  评论 - 59  阅读 - 7684

搜索【折半搜索】【双向BFS】【dfs剪枝优化+A*/IDA*】

折半搜索

meet in mid

对于枚举指数级别大的,分成2个部分枚举,再考虑进行答案的拼接合并。从O(ab)>O(ab/22)。拼接的方式可以是hash表查询,bitset标记,双指针单调性移动。

https://www.luogu.com.cn/problem/P5691】解方程,sigma(kixipi)=0,其中xi是需要你求出的不同解法,给出[1,m]的区间限制。n<=6.

正常枚举xi的每项O(1506),考虑分成左区间和右区间分别求sum然后合并,就可以了。
积累实现方式:对于一个很大的val,我要记录出现次数,(map),hash表查询。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define _f(i,a,b) for(register int i=a;i<=b;++i)
#define f_(i,a,b) for(register int i=a;i>=b;--i)
#define chu printf
#define ll long long
#define rint register int
#define ull unsigned long long
inline ll re()
{
    ll x=0,h=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')h=-1;
        ch=getchar();
    }
    while(ch<='9'&&ch>='0')
    {
        x=(x<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    return x*h;
}
const int N=300+10;
const int mod=5e6+7;
int P[153][9];
int n,m,k[9],p[9],mxp,table[mod+10],t[mod+10];
ll ans;
inline int Hash(int x)
{
    int v=(x>0)?(x%mod):((-x)%mod);
    while(t[v]&&table[v]!=x)
    {
        v++;if(v>=mod)v=0;
    }
    return v;
}
//int cnt=0;
inline void dfs1(int num,int val)
{
    if(num==(n>>1)+1)
    {
      //  ++cnt;
       // chu("%d %d:%d\n",(n>>1)+1,cnt,val);
        int pos=Hash(val);t[pos]++;table[pos]=val;
      //  chu("hash(%d):t[%d]:%d\n",val,pos,t[pos]);
        return;
    }
    _f(i,1,m)dfs1(num+1,val+P[i][p[num]]*k[num]);
}
inline void dfs2(int num,int val)
{
    if(num==n+1)
    {
        int pos=Hash(val);ans+=t[pos];return;
    }
    _f(i,1,m)dfs2(num+1,val-P[i][p[num]]*k[num]);
}
int main()
{
  
  // freopen("1.in","r",stdin);
  // freopen("1.out","w",stdout);
    n=re(),m=re();
    _f(i,1,n)k[i]=re(),p[i]=re(),mxp=max(mxp,p[i]);
    _f(i,1,m)
    _f(j,0,mxp)
    if(j==0)P[i][j]=1;
    else P[i][j]=P[i][j-1]*i;
    dfs1(1,0);
  // _f(i,0,5e6+6)
  // if(t[i])chu("t[%d]:%d\n",i,t[i]);
    dfs2((n>>1)+1,0);
    chu("%lld",ans);
    return 0;
}
/*
3
150
1 2
-1 2
1 2
*/

https://www.luogu.com.cn/problem/P3067】给出n个数,求把n个数取出若干个,若干个可以分成数值相同的2组的取法方案数。(n<=20)

对于一个数,有3种状态【1】选到A集合【2】选到B集合【3】不选,分别在累计sum的时候分+-号就行。问题变成把数分到3个集合让其中AB集合数sum相同的方案数,就是从左区间选出x个,右区间选出y个,让sum_x+sum_y=0的数集方案数,统计可以出现sum的个数然后求和就行。但是会出现重复,比如说同一个数集合,可能其中正负取不同都合法,但是只可以算一次-->(1)vis标记去掉重复(2)直接二进制数组记录所有状态,不累加方案而是去更新拼接的状态数,最后统计。
O(3n2)

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define _f(i,a,b) for(register int i=a;i<=b;++i)
#define f_(i,a,b) for(register int i=a;i>=b;--i)
#define chu printf
#define ll long long
#define rint register int
#define ull unsigned long long
inline ll re()
{
    ll x=0,h=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')h=-1;
        ch=getchar();
    }
    while(ch<='9'&&ch>='0')
    {
        x=(x<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    return x*h;
}
const int N=(1<<10)+100;
int a[22],n,mid;
ll ans;
bitset<N>vis[N],tmp;
map<int,bitset<N> >mp;
inline void ldfs(int now,int cost,int id)
{
	if(now==mid+1)
	{
		mp[cost].set(id,1);return;
	}
	ldfs(now+1,cost+a[now],id|(1<<(now-1)));
	ldfs(now+1,cost-a[now],id|(1<<(now-1)));
	ldfs(now+1,cost,id);
}
inline void rdfs(int now,int cost,int id)
{
	if(now==n+1)
	{
		if(mp[cost].count()==0)return;//没有
		tmp=mp[cost];//可以选择的数集合
		tmp&=(~vis[id]);
		ans+=tmp.count();
		vis[id]|=tmp;
		return;
	}
	rdfs(now+1,cost+a[now],id|(1<<(now-mid-1)));
	rdfs(now+1,cost-a[now],id|(1<<(now-mid-1)));
	rdfs(now+1,cost,id);
}
int main()
{
  // freopen("1.in","r",stdin);
  // freopen("1.out","w",stdout);
	n=re();mid=n>>1;
	_f(i,1,n)a[i]=re();
	ldfs(1,0,0);
	rdfs(mid+1,0,0);
	chu("%lld",ans-1);
    return 0;
}
/*
4 
1 
2 
3 
4 

*/

双向BFS

多起点互相奔赴,用size提前记录保证每个状态只更新了一轮。

https://blog.csdn.net/qq_29169749/article/details/51420097
在紫书上的搜索

*AandDFS

主要是剪枝和估价函数的计算。

posted on   HZOI-曹蓉  阅读(46)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

点击右上角即可分享
微信分享提示