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

输入:每组序列个数 序列

          如

          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;
}



你可能感兴趣的:(动态规划,ACM)