题解 | 数组划分

题目链接

题目:把含若干数字的数组任意划分成两个子数组,使得两个子数组的和相差最小。

本题采用3种解法,最后一种ac。

解法一:动态规划(数组和不大时可以采用,否则容易超时)

思路:设数组总和为sum,目标是找到一个子数组使得子数组和尽可能<=sum/2,这样两个数组和若相等,则和相差最小是0。

对于每一个数组中数字,都要更新dp数组:如果之前能凑出vec[i](数组元素),那么现在有了j,你就能凑出vev[i]+j了(前提是 vev[i]+j 不超过 target)

#include<stdio.h>
#include<vector>
#include<algorithm>
using namespace std;
int sum = 0;
int min_partition(vector<int> vec) {
	int target = sum / 2;//
	//dp[i]=true表示:和为i的数组能凑出
	vector<bool> dp(target + 1, false);
	dp[0] = true;
	//动态规划填表
	for (int i = 0; i<vec.size(); i++) {
		for (int j = target; j-vec[i] >=0; j--) {//逆着判断可以避免重复
			if (dp[j - vec[i]]) {
				dp[j] = true;
			}
		}
	}

	for (int i = target; i >= 0; i--) {
		if (dp[i]) {
			return i;//返回最接近target的和
			break;
		}
	}
	return -1;
}
int main(){
	vector<int> vec;
	int data;
	while (scanf("%d", &data)!=EOF) {
		vec.push_back(data);
		sum += data;
	}
	int a_sum = min_partition(vec);
	int b_sum = sum - a_sum;
	//降序输出两个元素和
	printf("%d %d", max(a_sum, b_sum),min(a_sum, b_sum));
	return 0;
}

解法二:贪心算法:先排序,依次把最大的数字插入和最小的数组中,快速得出近似出最优解!

#include<stdio.h>
#include<vector>
#include<algorithm>

using namespace std;
int sum = 0;
void min_partition(vector<int> &vec,int &a_sum,int &b_sum) {
	sort(vec.begin(), vec.end());
	int sub_sum = 0;
	for (int i = vec.size()-1; i>=0; i--) {//从大的数字开始,使得子数组和尽快接近总和的一半
		if (a_sum >= b_sum) {
			b_sum += vec[i];
		}
		else {
			a_sum += vec[i];
		}
	}
}
int main(){
	vector<int> vec;
	int data;
	while (scanf("%d", &data)!=EOF) {
		vec.push_back(data);
		sum += data;
	}
	int a_sum=0,b_sum= 0;
	min_partition(vec, a_sum, b_sum);
	//降序输出两个元素和
	printf("%d %d", max(a_sum, b_sum),min(a_sum, b_sum));
	return 0;
}

解法三:DSP+剪枝

思路:只要sa+vec[i]不超过数组总和的一半,就递归增加sa(保存子数组和)的值。

为了提高程序运行效率,先把数组降序排,预测更新全局最优的diff值,并且判断剪枝:如果预判发现 diff 已经是 0 或 1(理论极限),或者当前数字大到不可能产生更优解(2*vec[pos] > sum),就立刻设置 flag=true,停止一切后续搜索。

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<vector>
#include<algorithm>
using namespace std;
int sum = 0;
int diff = 0;//差值
bool flag = false;//是否剪枝
void dfs(vector<int>& vec, int pos, int sa) {
	if (pos == vec.size()||flag)return;//遍历完数组or需要剪枝
	int newdiff;
	 newdiff=abs(2 * (sa + vec[pos]) - sum);
	if (newdiff < diff) {//更新最小差值
		diff = newdiff;
		if (diff == 0 || diff == 1 || 2*vec[pos] > sum) {
			flag = true;//剪枝优化
		}
	}
   //1.vec[pos]可放入sa时
	if ((sa + vec[pos])*2 < sum) {//sa+ vec[pos]小于sum/2
		dfs(vec, pos + 1, sa + vec[pos]);//往sa继续加数据
	}
	//2.vec[pos]不放入sa时
	dfs(vec, pos + 1, sa);
}
bool compare(int l, int  r) {
	return l > r;
}
int main(){
	vector<int> vec;
	int i;
	while (scanf("%d", &i) != EOF) {
		vec.push_back(i);
		sum += i;
	}
	diff = sum;//初始化差值上限
	sort(vec.begin(), vec.end(),compare);//降序排
	dfs(vec, 0, 0);
	int sa = (sum - diff) / 2;//diff=(sum-sa)-sa=sum-2*sa
	printf("%d %d\n", sa + diff, sa);//降序输出
    return 0;
}

计算机复试机试(王道版) 文章被收录于专栏

收录王道2026年计算机复试机试的(课程)代码题解,仅供个人学习参考

全部评论

相关推荐

晚上和一个老哥聊天,加深了自己对一些事情的思考就是一个人在公共场合敢实名表达自己的感受,自己的思考,自己的观点,是一件需要非常非常大勇气的事情,这意味着你触达内心的想法感受,会被大众所注视,审判,而绝大多数人都会异常在意别人对自己的看法,所以当大规模的眼光都看在你身上的时候,这种压力不是谁都能抗下来的。小一点的是在朋友圈写小作文发表自己内心的想法,之前我是能经常看到不少同学吃一个东西&nbsp;或者&nbsp;去一个地方玩然后长篇大论写下自己感受的朋友圈,但现在我也很少在朋友圈看到这些内容了,大家是长大了,开始忽略这些感受了,还是越来越不愿意拿出来分享了……大一点是直接做自媒体,更大范围地展示自己,直接向全互联网的人述说自己的经历,表达自己的想法,展示自己性感的大脑,让互联网的所有人凝视你,审判你,赞扬你,诋毁你……说实话,这非常像把自己扒光了游街示众的感觉,只有真正在互联网上实名发表过这种口播视频之后,才懂这种感觉有多奇妙哈哈哈我们不说钱不钱的问题,关说对个人能力的提升,这非常锻炼人,非常非常锻炼人,你的表达能力,你的心理素质都在全方面提升,你的心理抗压能力也会不断提升,因为无论怎么说都有人骂你,你说苹果手机好用,都有人骂你叛国贼[捂脸][捂脸][捂脸]一开始最大的障碍就是怕熟人看到,特别尴尬,怕大家议论你,嘲笑你,但其实真的有那么多人关注你吗?真的有那么多人嘲笑你吗?可能都是自己在臆想,出现幻觉了就算真的有人当面嘲笑你,这又怕什么呢,我始终坚信一个真正从0到1在某个领域做成功一件事的人(标准:得到这个领域人的普遍认可)是不会嘲笑一个开始很笨拙的人,因为谁不是这样走过来的?谁一开始就做的很好,谁刚开始做就很随心所欲,是你吗?一个健身大神会嘲笑一个刚入健身房的新手吗?一个高级程序员会嘲笑一个刚学会打hello&nbsp;world的新手吗?一个减肥成功的人会嘲笑刚开始跑几步路就喘的胖子吗?一个作家会嘲笑刚开始写小作文词不达意语句不通顺的菜鸟吗?一个人但凡能嘲笑你,那就证明他没做成哪怕至少一件事,没在一个领域得到绝大多数人的普遍认可,这种人的嘲笑是多么无力,这是他无能的狂怒,他自己不敢,自己半途而废,他怕你做成了,证明他自己是废物而已(这里说话比较难听)从我刚开始从化学跨行当程序员时,我就开始向外展示这些事情,然后无论在现实里还是在互联网上,我都听过非常非常多嘲笑的声音,否定的声音,所以我一度非常敏感,非常脆弱在大二这一年我几乎不敢见人,我每天吃喝拉撒都在实验室的小工位,我怕出去会被人嘲笑,会被否定,因为随随便便一句话我就能蹲在天台哭一晚上,直到我突然进了美团的日常实习,直到我突然进了字节的暑期实习,直到我秋招又拿了字节的offer,这个时候我已经站在高处,我回头看,我向下看,之前那些否定嘲笑的声音早已听不见,我已经在山上了,而他们又在哪呢?而我发现当时那些鼓励我,认可我,支持我的兄弟们,不是那些已经在某个领域取得一定成果的人,就是那些同样在路上的同伴,好像只有这些人,他们才会对蹒跚学步的新手给予鼓励与帮助……最后居然戏剧性地来了一个callback&nbsp;呼应了我大一演小品的一句台词且视他人之疑目如盏盏鬼火大胆地去走你的夜路!这是我自己的亲身经验,也是我想表达,传递的内容,想干什么就去干吧,至于别人怎么看,随他吧,反正弱者才会嘲笑你,强者都会向你伸出援手……
牛友故事会
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务