求把一个序列分为两个两组,两组各自和相差最小的最大的那个和

这篇博客探讨了如何将一个序列分成两组,使得两组的和之间的差值最小,并给出了一个具体的例子:输入序列5个元素1 3 3 3 7和6个元素4 1 4 4 15 4,输出分别为9和16。博主最初尝试用深度搜索,但发现时间复杂度过高,于是转向动态规划。通过最长上升子序列的思路,博主意识到每个元素有两种可能,即属于两组之一。解决方案是先固定最后一个元素的组别,然后从前向后遍历,寻找使和接近目标值的元素分配方式。这种问题的特点在于元素位置的不确定性,可以类比zoj 1196 Fast Food的问题。程序实现未给出。

输入:每组序列个数 序列

          如

          5
          1 3 3 3 7

          6
           4 1 4 4 15 4

输出:

          9

          16

分析: 一开始因为每个数有可能分到第一组,也可能分到第二组。所以一开始想的是深度搜索。但是

           显然时间会超出。后来想动态规划,一直没有想明白。终于在第二天早上想出来了。当时想到

           最长上升子序列,对于每一个元素有可能出现在序列中也能没有。比如,站队要想从左到右个子

           从高到低排列,那么必然要踢掉一些人。每个人都有两种可能,留下或踢掉。当时采取的策略是,

          自顶向下的话,是找前面比当前的身高矮的人,然后 temp = dp[j] + 1; 求一个最大的temp。所以

          对于这个我们也可找前面的元素,然后默认它跟当前的在同一个组里,然后求一个离目标值最接近

          的值。以为每一个数必须出现在一个组中,那么我们先选定最后一个数的组。

          再联系zoj 1196 Fast Food的类似做法,发现此类的特点是前面元素的具体位置是不定的,想一个

          游码,所以一个for循环就是用来遍历它的。

程序:

#include "iostream"
#include <cmath>
#include <cstdio>
#include <cstring>
using namespace std;

int a[100], result[100][1024];

int dp(int n, int value){
    if(result[n][value] != -1)
        return result[n][value];
	if(n == 0)
		return 0;
	int min = 0xffffff, i;
	for(i = 0; i < n; i++){
		int temp = dp(i, value - a[n]) + a[n];
		if(fabs(value - temp) < fabs(min - value))
			min = temp;
	}
	result[n][value] = min;
	return min;
}

int main(){
	//freopen("in.txt", "r", stdin);
	int n, i;
	while(cin>>n){
		memset(result, -1, sizeof(result));
		int sum = 0;
		for(i = 1; i <= n; i++){
			cin>>a[i];
			sum += a[i];
		}
		int temp = dp(n, sum / 2);
		if(temp < sum - temp)
			temp = sum - temp;
		cout<<temp<<endl;
	}
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值