【解题报告】2020蓝桥杯B组模拟 计蒜客 结果填空:苹果

问题描述

有 3030 个篮子,每个篮子里有若干个苹果,篮子里的苹果数序列已经给出。

现在要把苹果分给小朋友们,每个小朋友要么从一个篮子里拿三个苹果,要么从相邻的三个篮子里各拿一个苹果。

苹果可以剩余,而且不同的拿法会导致不同的答案。比如对于序列3 1 3 ,可以分给两个小朋友变成0 1 0;也可以分给一个小朋友变成2 0 2,此时不能继续再分了。所以答案是 22 。

求问对于以下序列,最多分给几个小朋友?


只要是求最多or最少,95%都是宽搜或深搜的思路

网上有很多用贪心解的博客, 压根不对, 本题贪心只能出样例, 换个刁钻点的数据就错了。

正确的思路是DFS,拿取个数只有两种操作, 要么单一-3,要么相邻三个-1, 那么只要用深搜模拟, 对每种可能性进行遍历, 自然可以求出最小值。


需要注意: 如果单纯的用搜索跑, 那么每一个数字都有取相邻两个各减一和取这个数字减三的操作, 也就是说, 需要跑3的30次方次,对于计算机来说还是很慢的, 因此需要用剪枝优化一下。


参考代码

#include<bits/stdc++.h>
using namespace std;

int ans = 0; 
int a[117] = {
    
    7,2,12,5,9, 9,8,10,7,10, 5,4,5,8,4, 4,10,11,3,8, 7,8,3,2,1, 6,3,9,7,1};
int sum[117];

void dfs(int idex, int num) {
    
    
	if(idex == 30) {
    
    
		ans = max(ans, num);
		return;
	}
	if(sum[idex] / 3 + num < ans) return; 	//剪枝优化
	//不公用
	dfs(idex+1, num+a[idex]/3);
	//往后公用 
	if(idex+2 < 30) {
    
    
		int min_num = min(a[idex], a[idex + 1]);
		min_num = min(min_num, a[idex+2]);		//共用最多能分几个
		for(int k = 1; k <= min_num; k++) {
    
    
			for(int i = 0; i < 3; i++) a[idex+i] -= k;
			dfs(idex+1, num+a[idex]/3+k);
			for(int i = 0; i < 3; i++) a[idex+i] += k;
		} 
	} 
}

int main() {
    
    
    for(int i = 29; i >= 0; i--) sum[i] = sum[i + 1] + a[i];
    for(int i = 0; i < 30; i++) cout << sum[i] << ' ';
    dfs(0, 0);
    cout << ans << endl;
    return 0;
}


拨云见日 未来可期

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_43899069/article/details/109098805
今日推荐