一个有序序列,分成两组,使差的绝对值最小

RabbitLBJ 2012-03-12 04:41:22
一个有序序列,偶数个,分成两组(个数要相同),使差的绝对值最小,求算法

暂时没想到好的解法,求高人
...全文
1227 15 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
gao364316764 2012-04-03
  • 打赏
  • 举报
回复
这个算法就挺好的,只不过在求sum1和sum2时从大数开始加更好,更精确。
[Quote=引用 3 楼 的回复:]

C/C++ code

public static void main (String arg[]) {
int a[] = { 2, 3, 6 ,9};
int sum1 = 0, sum2 = 0;
int tmp = 0;

for (int i = 0; i < a.length; i++) {
f……
[/Quote]
hen_hao_ji 2012-04-03
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 的回复:]
引用 1 楼 nice_cxf 的回复:

先求和sum,然后/2,题目转换为从n个数据中挑选n/2个,使和最接近sum/2,这个似乎有人问过,可以查一下


我试试
[/Quote]
可以用动态规划,类型于背包问题,加一维用来表示当前由几个数组合成就可以了。。
RabbitLBJ 2012-04-03
  • 打赏
  • 举报
回复
顶下,还是直接求代码吧,惭愧了
muyi66 2012-03-12
  • 打赏
  • 举报
回复
迭代交换算法,时间复杂度函数极差,对不不了大序列。但可以保证最终结果的正确性。
    //  将序列对折拆分入两组:ga、gb,gd中保存组差sum(gb)-sum(ga)
int gl=??; // gl中保存组长度
int flag;
do
{
flag=0;
for (int i=0;i<gl;i++) // 寻找交换后能缩减两组差额绝对值的数对
{
for (int j=0;j<gl;j++)
{
if (abs(ga[i]-gb[j]+gd)<abs(gd))
{
// 交换ga[i]、gb[j]
flag=1;
gd=gb[j]-ga[i]+gd;
goto next;
}
}
}
next:
}while(flag); // 若没有发生交换事件,则已找到最佳拆分
muyi66 2012-03-12
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 rabbitlbj 的回复:]

再顶下,貌似办法还是不怎么好,这个高人再指点指点,谢谢
[/Quote]这个算法没测试过,不过应该要比前面的好点了。
//  首先还是逆序排序
int cc=序列长度;
int ds=0; // 记录b组和与a组和的差额
int al=0,bl=0; // 记录a组及b组的长度
for (int i=0;i<序列长度;i++)
{
if (ds>0)
{
// a组更小,将当前数加入a组
if (++al>=cc/2)
break;
}
else
{
// b组更小,将当前数加入b组
if (++bl>=cc/2)
break;
}
}
for (;i<序列长度;i++) // 若还有剩余数字,则加入未满组
if (al<cc/2)
{
// 将当前数添加入a组
al++;
}
else
{
// 将当前数添加入b组
}
RabbitLBJ 2012-03-12
  • 打赏
  • 举报
回复
再顶下,貌似办法还是不怎么好,这个高人再指点指点,谢谢
muyi66 2012-03-12
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 rabbitlbj 的回复:]

引用 5 楼 muyi66 的回复:

差怎么定义的?两两配对相减吗?

如果是这样的话,我想可以这么做:

首先将序列排序,降序排列。

然后进入循环进行处理,维护一个差值变量ds——表达目前B组减去A组的差值,初始化为0。
循环体里判断ds值,若大于0则将序列中当前位置的数加入A组下一位置的数加入B组,否则相反。
添加之后刷新ds值,维护循环控制变量,再次循环。

这……
[/Quote]个数是相当的,不过保证不了绝对值最小。
RabbitLBJ 2012-03-12
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 nice_cxf 的回复:]

先求和sum,然后/2,题目转换为从n个数据中挑选n/2个,使和最接近sum/2,这个似乎有人问过,可以查一下
[/Quote]

我试试
RabbitLBJ 2012-03-12
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 kuzuozhou 的回复:]

C/C++ code

public static void main (String arg[]) {
int a[] = { 2, 3, 6 ,9};
int sum1 = 0, sum2 = 0;
int tmp = 0;

for (int i = 0; i < a.length; i++) {
f……
[/Quote]

和楼上同样的问题,你把9改成1000,这样会生成{1000}和{2,3,6}两个集合
RabbitLBJ 2012-03-12
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 muyi66 的回复:]

差怎么定义的?两两配对相减吗?

如果是这样的话,我想可以这么做:

首先将序列排序,降序排列。

然后进入循环进行处理,维护一个差值变量ds——表达目前B组减去A组的差值,初始化为0。
循环体里判断ds值,若大于0则将序列中当前位置的数加入A组下一位置的数加入B组,否则相反。
添加之后刷新ds值,维护循环控制变量,再次循环。

这样就保证每次加入时总是在试图纠正偏差。

……
[/Quote]

可是这样不能保证个数相当,比如第一个数非常大,后面的数很小,那前面一个集合只包含第一个数,后面集合包含余下所有数
muyi66 2012-03-12
  • 打赏
  • 举报
回复
差怎么定义的?两两配对相减吗?

如果是这样的话,我想可以这么做:

首先将序列排序,降序排列。

然后进入循环进行处理,维护一个差值变量ds——表达目前B组减去A组的差值,初始化为0。
循环体里判断ds值,若大于0则将序列中当前位置的数加入A组下一位置的数加入B组,否则相反。
添加之后刷新ds值,维护循环控制变量,再次循环。

这样就保证每次加入时总是在试图纠正偏差。
pengfoo 2012-03-12
  • 打赏
  • 举报
回复
仅供参考
pengfoo 2012-03-12
  • 打赏
  • 举报
回复

public static void main (String arg[]) {
int a[] = { 2, 3, 6 ,9};
int sum1 = 0, sum2 = 0;
int tmp = 0;

for (int i = 0; i < a.length; i++) {
for (int j = 0; j < a.length; j++) {
if (a[i] > a[j]) {
tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
}
}
for (int i = 0; i < a.length; i++) {
if (sum1 < sum2) {
sum1 += a[i];
} else {
sum2 += a[i];
}
}
System.out.println(Math.abs(sum1 - sum2));
}

蓝枫10 2012-03-12
  • 打赏
  • 举报
回复
可以把所有数求和,然后除以2!
然后从大到小去选择n/2个数,使它的和最接近上面那个数····
不知道能实现不
先mark下
nice_cxf 2012-03-12
  • 打赏
  • 举报
回复
先求和sum,然后/2,题目转换为从n个数据中挑选n/2个,使和最接近sum/2,这个似乎有人问过,可以查一下

65,186

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧