1. 问题描述:

  有两个数组a,b,大小都为n,数组元素的值任意整形数,无序;
  要求:通过交换a,b中的元素,使[数组a元素的和]与[数组b元素的和]之间的差最小。

2. 求解思路:

当前数组a和数组b的和之差为
    A = sum(a) - sum(b)
    a的第i个元素和b的第j个元素交换后,a和b的和之差为
    A' = sum(a) - a[i] + b[j] - (sum(b) - b[j] + a[i])
        = sum(a) - sum(b) - 2 (a[i] - b[j])
        = A - 2 (a[i] - b[j])
    设x = a[i] - b[j], 则 |A'| = |A-2x|
    假设A > 0, 
    当x在(0,A)之间时,做这样的交换才能使得交换后的a和b的和之差变小,x越接近A/2效果越好, 如果找不到在(0,A)之间的x,则当前的a和b就是答案。
    所以算法大概如下:
    在a和b中寻找使得x在(0,A)之间并且最接近A/2的i和j,交换相应的i和j元素,重新计算A后,重复前面的步骤直至找不到(0,A)之间的x为止。

3. C语言实现

 #include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define N 100
int A[N];
int B[N];
//随机初始化一个数组
void init(int a[], int n)
{
int i;
for(i = ; i < n; ++i)
a[i] = rand() % N;
}
//输出数组
void print(int a[], int n)
{
int i;
for(i = ; i < n; ++i)
printf("%d ", a[i]);
printf("\n--------------------------------------------\n");
} //求数组和
int sum(int a[], int n)
{
int i, sum = ;
for(i = ; i < n; ++i)
sum += a[i];
return sum;
}
//交换整数
void swap(int *a, int *b)
{
int temp = *a;
*a = *b;
*b = temp;
}
//n1,n2为数组A和B中实际初始化的元素个数
int solve(int n1, int n2)
{
int i, j; //循环迭代变量
int x, y; //用于保存可交换数字对的索引
int maxSum, minSum; //分别用于保存两个数组的数字之和
int diff; //diff = sum1 - sum2
int maxdiff; // 2 * (A[x] - B[y])
int flag; //标记是否找到可交换的数字对
int temp;
int *pMax; //指向数字总和较大的数组
int *pMin; //指向数字总和较小的数组 //随机初始化数组
init(A, n1);
init(B, n2);
print(A, n1);
print(B, n2);
//求数组中数字之和
maxSum = sum(A, n1);
minSum = sum(B, n2); if(maxSum == minSum)
{
printf("There is no need to swap!\n");
return ;
} //令pMax和pMin分别指向数字总和大的数组以及总和小的数组
pMax = A;
pMin = B;
if(maxSum < minSum)
{
pMax = B;
pMin = A;
swap(&maxSum, &minSum);
}
//循环交换两个数组中的数字对,在交换的过程中,始终
//保持pMax数组的数字总和大于或者等于pMin数组的数字总和。
//也就是保持diff >= 0
diff = maxSum - minSum;
while()
{
flag = ;
x = y = ;
maxdiff = ;
//寻找能够使diff减小的数字对。
//从趋势上来看,
//减小的幅度越大diff收敛的越快,
//while循环的次数也越少
for(i = ; i < n1; ++i)
{
for(j = ; j < n2; ++j)
{
temp = pMax[i] - pMin[j];
if(temp > && (diff - * temp) >= )
{
if(maxdiff < *temp)
{
maxdiff = * temp;
x = i;
y = j;
flag = ;
}
}
}
}
if(flag) //找到了可以使diff减小的数字对
{
printf("swap, pMax[%d]:%d, pMin[%d]:%d\n", x, pMax[x], y, pMin[y]);
diff -= maxdiff;
swap(pMax + x, pMin + y);
print(A, n1);
print(B, n2);
printf("diff = %d\n", diff); }
else //没有找到可以交换的数字对,终止while循环
{
break;
}
}
return diff; //返回两个数组经交换后的最小差值
} int main(int argc, char **argv)
{ srand(time(NULL));
printf("min difference:%d\n", solve(, ));
// system("pause");
// pause();
return ;
}

 4. java实现

 import java.util.Arrays;

 /**
*
* @author Administrator
*
*/
public class TestUtil {
private int[] arrysMin = null; private int[] arrysMax = null; private int matchNum = 0; private boolean hasMatched = false; /**
* 返回数组的所有元素的总和
*
* @param arrays
* 待计算数组
* @return 所有元素的总和值
*/
public int getArraySum(int[] arrays) {
int sum = 0;
if (null != arrays) {
for (int i : arrays) {
sum += i;
}
}
return sum;
} /**
* 返回数组的差值
*
* @param array1
* 集合一
* @param array2
* 集合二
* @return 差值
*/
public int getTowArraysMacth(int[] array1, int[] array2) {
Integer l1 = getArraySum(array1);
Integer l2 = getArraySum(array2); if ((l1 - l2) / 2 > 0) {
arrysMax = array1;
arrysMin = array2;
return (l1 - l2) / 2;
} else {
arrysMax = array2;
arrysMin = array1;
return (l2 - l1) / 2;
}
} private boolean isReturn(int[] arrayMax, int[] arrayMin) {
Integer l1 = getArraySum(arrayMax);
Integer l2 = getArraySum(arrayMin); if ((l1 - l2) > 0) {
return false;
} else {
return true;
}
} public void doMatch() {
// 保证大的数组总和永远是大的,以防递归进入死循环
if (isReturn(arrysMax, arrysMin)) {
return;
}
// 获取元素总和大的与小的差值平均值
int diff = getTowArraysMacth(arrysMax, arrysMin);
// 使用一个大数字初始化最小绝对值,后面做比较
int abs = getArraySum(arrysMax);
int tempElement = 0;
// 最终大数组要交换的下标
int maxIndex = -1;
int minIndex = -1;
if (null != arrysMax && null != arrysMin) {
for (int i = 0; i < arrysMax.length; i++) {
for (int j = 0; j < arrysMin.length; j++) {
int temp = arrysMax[i] - arrysMin[j];
if (temp > 0 && diff > temp) {
// 如果元素差值和元素总和大的与小的差值平均值正好相等,直接交换元素OK
if (Math.abs(diff - temp) == 0) {
tempElement = arrysMin[j];
arrysMin[j] = arrysMax[i];
arrysMax[i] = tempElement;
matchNum++;
hasMatched = true;
return;
} else {
// 否则完全遍历,最终找出元素差值和总和差值平均值差距最小的两元素,
if (abs > Math.abs(diff - temp)) {
abs = Math.abs(diff - temp);
maxIndex = i;
minIndex = j;
}
}
}
}
}
//如果没有找到匹配项,且在已变换的数组中找到了满足条件的变量,则继续递归
if (!hasMatched && (maxIndex != -1 || minIndex != -1)) {
// 交换差距最小的两元素
System.out.printf("第%d次交换, Max[%d]:%d, Min[%d]:%d\n", ++matchNum, maxIndex, arrysMax[maxIndex], minIndex, arrysMin[minIndex]);
tempElement = arrysMin[minIndex];
arrysMin[minIndex] = arrysMax[maxIndex];
arrysMax[maxIndex] = tempElement;
System.out.println("交换后Max数组:" + Arrays.toString(arrysMax));
System.out.println("交换后Min数组:" + Arrays.toString(arrysMin));
System.out.println();
// 递归
doMatch();
}
}
} public int getMatchNum() {
return matchNum;
} /**
* @param args
*/
public static void main(String[] args) {
TestUtil tu = new TestUtil();
int[] a1 = { 11, 2, 4, 6, 47 };
int[] a2 = { 4, 5, 8, 9, 2 };
System.out.println("交换前数组a1:" + Arrays.toString(a1));
System.out.println("交换前数组a2:" + Arrays.toString(a2));
// 进行第一次分出,两元素的总和谁大谁小
tu.getTowArraysMacth(a1, a2);
// 开始进行处理交换
tu.doMatch();
// 打印交换结果
System.out.println("交换次数:" + tu.getMatchNum());
System.out.println("a1数组元素和:" + tu.getArraySum(a1));
System.out.println("a2数组元素和:" + tu.getArraySum(a2));
System.out.println("交换后原数组a1:" + Arrays.toString(a1));
System.out.println("交换后原数组a2:" + Arrays.toString(a2));
}
}

参考链接:http://blog.csdn.net/kittyjie/article/details/4386742

      http://www.myexception.cn/program/758365.html (此页面中的java实现是有问题的,本文已对其作出修改)

如何交换两个等长整形数组使其数组和的差最小(C和java实现)的更多相关文章

  1. 有两个数组a,b,大小都为n,;通过交换a,b中的元素,使sum(a)-sum(b)最小。

    有两个数组a,b,大小都为n,数组元素的值任意整形数,无序: 要求:通过交换a,b中的元素,使数组a元素的和与数组b元素的和之间的差最小. 当前数组a和数组b的和之差为    A = sum(a) - ...

  2. The Super Powers UVA 11752 分析分析 求无符号长整形以内的数满足至少可以用两种不同的次方来表示。比如64 = 2^6 = 8^2; 一个数的1次方不算数。

    /** 题目:The Super Powers UVA 11752 链接:https://vjudge.net/contest/154246#problem/Y 题意:求无符号长整形以内的数满足至少可 ...

  3. C/C++ 中的0长数组(柔性数组)

    转自C/C++ 中的0长数组(柔性数组) 在标准C和C++中0长数组如charArray[0]是不允许使用的,因为这从语义逻辑上看,是完全没有意义的.但是,GUN中却允许使用,而且,很多时候,应用在了 ...

  4. 实现pow(int x, int y),即x的y次方 ; 异或交换两个数;

    问题1:实现pow(int x, int y) ,即x的y次方 x的y次方就是有y个x连续乘机,代码如下: #include <stdio.h> #include <stdlib.h ...

  5. URAL 1297 最长回文子串(后缀数组)

    1297. Palindrome Time limit: 1.0 secondMemory limit: 64 MB The “U.S. Robots” HQ has just received a ...

  6. 编程技巧:使用异或操作符(XOR)交换两数值

    异或(exclusive OR)作为4种逻辑操作符之一,相对其他3种(OR/AND/NOT)来说,出场的次数非常少,是因为在日常开发中能用到它的场景本来就不多.对笔者来说,目前接触到场景只有交换两个数 ...

  7. 面试题-JavaScript交换两个变量的方法

    在平时的业务开发或者面试过程中,经常会遇到交换两个变量这种问题,于是,个人总结以下几种交换变量的方法: 1.方案一 使用一个临时变量来交换  2.方案二 使用ES6解构赋值语法来交换 3.方案三利用数 ...

  8. Java 交换两数的方法

    错误示范 1. 直接交换 public class SwapNumbers { // 直接交换 public static void swap(int a, int b) { int temp = a ...

  9. (持续更新)虚树,KD-Tree,长链剖分,后缀数组,后缀自动机

    真的就是讲课两天,吸收一个月呢! \(1.\)虚树 \(2.\)KD-Tree \(3.\)长链剖分 \(4.\)后缀数组 后缀数组 \(5.\)后缀自动机 后缀自动机

随机推荐

  1. JS基本内容

    js是网页的脚本语言,它也是有内嵌和外部两种,样式是写在头部,脚本语言可以写在任何位置,通常写在网页底部:<script type="texe/javascript"> ...

  2. R 报错:package ‘***’ is not available (for R version ****) 的解决方案

    R 安装sparklyr,ggplot2等包出现如下warning package '****' is not available (for R version 3.0.2) 系统环境 ubuntu1 ...

  3. 用自己的算法实现startsWith和endsWith功能

    package hanqi; import java.util.Random; import java.util.Scanner; public class zuoye { public static ...

  4. python中xrange和yield的用法

    相信很多人对xrange和yield都不是很清楚,网上很多文章也是写的云里雾里的,今天我用最简单的例子给大家说下. 说起xrange的时候就一定要提range,其实xrange 用法与 range 完 ...

  5. MyEclipse xml 手动添加 dtd

    <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "- ...

  6. LPC43XX JTAG Scan Chain

    Debug and trace functions are integrated into the ARM Cortex-M4. Serial wire debug and trace functio ...

  7. Web app 的性能瓶颈与性能调优方法

    1. web app 性能测试工具使用 2. mysql 性能分析与调优方法

  8. The Truth About .NET Objects And Sharing Them Between AppDomains

    From http://geekswithblogs.net/akraus1/archive/2012/07/25/150301.aspx I have written already some ti ...

  9. centos 7 /etc/rc.local 开机不执行的问题

    最近发现centos7 的/etc/rc.local不会开机执行,于是认真看了下/etc/rc.local文件内容的就发现了问题的原因了 1 2 3 4 5 6 7 8 9 10 11 #!/bin/ ...

  10. 如何修改 EM12c 中 SYSMAN 用户的密码?

    以下内容全部转自:http://www.chenjunlu.com/2013/04/how-to-modify-the-password-for-sysman-of-em-12c-cloud-cont ...