题解:P9234 [蓝桥杯 2023 省 A] 买瓜

题目传送门

P9234 [蓝桥杯 2023 省 A] 买瓜

$\ $
$\ $
这么小的 \(n\) 我们肯定优先考虑暴力枚举,然后发现这个傻篮子时间是 \(\displaystyle \mathcal O(3^{\mathcal n})\)

吓哭了。发现我们不用很难受的去从头到尾枚举,可以先枚举一半,再去根据另一半枚举的结果去 \(\operatorname {check}\)

其实很明显我们这时候就可以祭出剪枝大法了,剪枝大法好!
直接暴力的时候 now_sum > m 的时候直接滚蛋不往下搜就好了。


下面给出可爱的伪代码 - 防止抄袭
\(\mathcal {L\ a\ p\ p\ l\ a\ n\ d\ \_\ F\ o\ r\ e\ v\ e\ r}\)

const int N=31;
int n,m,ans=35,a[N];
unordered_map<int,int>哈希表;

inline void 前半搜索(int st,int ed,int sum,int cnt)//起点,终点,当前瓜重,刀数 
{ 
//前一半搜索产生状态 
	if(sum>m)return;
	if(st==ed){
		if(哈希表.是否更新过(sum))哈希表[sum]=min(哈希表[sum],cnt);
		else 哈希表[sum]=cnt;
		return;
	}
	
	//不买瓜,不加刀数  
	前半搜索(st+1,ed,sum,cnt);
	//买一半的挂,加刀数  
	前半搜索(st+1,ed,sum+a[st]/2,cnt+1);
	//买瓜,不加刀数,因为不用劈  
	前半搜索(st+1,ed,sum+a[st],cnt);
}

inline void 后半搜索(int st,int ed,int sum,int cnt)
{
//后一半搜索进行check 
	if(sum>m)return;
	if(st==ed){
		if(哈希表.是否更新过(m-sum))ans=min(ans,cnt+哈希表[m-sum]);
		return;
	}
	
	//思路同上,但是这时候因为是倒序搜索,所以a[]下标要用ed  
	后半搜索(st,ed-1,sum,cnt);
	后半搜索(st,ed-1,sum+a[ed]/2,cnt+1);
	后半搜索(st,ed-1,sum+a[ed],cnt);
}

main(void){
	输入(n)(m);m*=2;
	for(int i=1;i<=n;i++){输入(a[i]);a[i]*=2;}
	sort(a+1,a+1+n);//保证数组有序来玄学剪枝。 
	
	//折半 
	int mid=n/2;
	前半搜索(1,mid+1,0,0);
	后半搜索(mid,n,0,0);
	
	if(ans==35)输出("-1");
	else 输出(ans);
}
posted @ 2025-11-14 21:32  Noivelist  阅读(12)  评论(0)    收藏  举报