找回密码
 欢迎注册
查看: 18562|回复: 5

[讨论] 求两数组差的绝对值最小值

[复制链接]
发表于 2009-10-2 17:23:59 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?欢迎注册

×
本帖最后由 sir_chen 于 2009-10-2 18:27 编辑

有一个长度为n的数组a[n],暂不规定数组元素的类型,将这个数组划分成两个子数组,记这两个子数组的和分别为S1,S2,记两子数组和的差的绝对值ΔS=|S1-S2|.现在的问题是如何分组才能使ΔS最小.
我编了几个程序,但是时间复杂度都是O(2n),但是用lingo编程发现算的很快.不知道lingo是怎么实现的,感觉这道题有点类似0-1背包问题,但约束要少一些.
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2009-10-2 21:35:39 | 显示全部楼层
两个子数组的size确定不?
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2009-10-3 13:12:58 | 显示全部楼层
实际上是将原数组进行一个分划,从原数组中选出若干个元素作为第一个子数组,剩下的就是第二个子数组的.两个子数组的元素个数不确定.
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2009-10-3 13:26:08 | 显示全部楼层
本帖最后由 sir_chen 于 2009-10-3 13:41 编辑

记两个子数组分别为$A_0,A_1$
记$x_k={(0,(a_k in A_0)),(1,(a_k in A_1)):}$
那么$DeltaS=|sum_{k=1}^{n}x_k a_k-sum_{k=1}^{n}(1-x_k)a_k|=|2sum_{k=1}^{n}x_k a_k-S_n|$
现在的任务是如何确定0-1变量$x_k$,使得$DeltaS$最小
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2009-10-9 15:40:09 | 显示全部楼层
这个是动态规划题.所有n个整数和为S,那么可以用O(S)的空间复杂度和O(n*S)的时间复杂度解决.
这个问题CSDN上经常讨论过
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2009-10-13 11:02:55 | 显示全部楼层
给出我的代码,效率比较低,采用动态规划做得
复杂度 O(sum * s1*s2)

原ACM题是将一数组化分为两数组, 使得他们和的差最小
同时两数组元素个数的差不超过1

#include <algorithm>
#include <numeric>
#include <bitset>
#include <vector>
using namespace std;

# define MAXN 100
# define MAXS 450

bitset<(MAXN + 1)*MAXS / 2> bs[MAXN / 2 + 1];
vector<int> vec[MAXN /2 + 1];

// 4 1 2 4 10
int dp(int a[], int n)
{
        std::sort(a + 1, a + n + 1);
        if (n <= 2){
                printf("%d %d\n", a[n - 1], a[n]);
                return 0;
        }

        int sum = accumulate(a + 1, a + 1 + n, 0);
        int minsum = a[1];
        int maxlev = (n + 1) / 2;

        bs[1].set(a[1]);
        vec[1].push_back(a[1]);

        for (int i = 2; i <= n; i++){
                int curlev = min(i, maxlev); //update current curlev

                for (int j = curlev - 1; j >= 0; j--){
                        for (int k = vec[j].size() - 1; k >= 0; k--){
                                int suma = vec[j][k] + a[i];
                                if (suma <= sum / 2 && !bs[j + 1].test(suma)){
                                        if (j + 1 < maxlev){
                                                bs[j + 1].set(suma);
                                                vec[j + 1].push_back(suma);
                                        }
                                        if (suma > minsum){
                                                if (j + 1 == maxlev && n % 2 == 0)
                                                        minsum = suma;
                                                else if (j + 2 >= maxlev && n % 2 == 1)
                                                        minsum = suma;
                                                if (minsum + 1 >= sum / 2)
                                                        break;
                                        }
                                }
                        }
                }
        }
        printf("%d %d\n", minsum, sum - minsum);
}

int main( )
{
        int n;
        int a[MAXN + 1] = {0};
        scanf("%d", &n);
        for (int i = 1; i <= n; i++)
                scanf("%d", a + i);
        dp(a, n);
        return 0;
}
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
您需要登录后才可以回帖 登录 | 欢迎注册

本版积分规则

小黑屋|手机版|数学研发网 ( 苏ICP备07505100号 )

GMT+8, 2024-5-8 08:02 , Processed in 0.053354 second(s), 16 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表