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

2166

被折叠的 条评论
为什么被折叠?



