找回密码
 欢迎注册
查看: 31672|回复: 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 #include #include #include using namespace std; # define MAXN 100 # define MAXS 450 bitset<(MAXN + 1)*MAXS / 2> bs[MAXN / 2 + 1]; vector 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-12-29 09:49 , Processed in 0.022607 second(s), 16 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

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