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语言实现

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <time.h>
  4. #define N 100
  5. int A[N];
  6. int B[N];
  7. //随机初始化一个数组
  8. void init(int a[], int n)
  9. {
  10. int i;
  11. for(i = ; i < n; ++i)
  12. a[i] = rand() % N;
  13. }
  14. //输出数组
  15. void print(int a[], int n)
  16. {
  17. int i;
  18. for(i = ; i < n; ++i)
  19. printf("%d ", a[i]);
  20. printf("\n--------------------------------------------\n");
  21. }
  22.  
  23. //求数组和
  24. int sum(int a[], int n)
  25. {
  26. int i, sum = ;
  27. for(i = ; i < n; ++i)
  28. sum += a[i];
  29. return sum;
  30. }
  31. //交换整数
  32. void swap(int *a, int *b)
  33. {
  34. int temp = *a;
  35. *a = *b;
  36. *b = temp;
  37. }
  38. //n1,n2为数组A和B中实际初始化的元素个数
  39. int solve(int n1, int n2)
  40. {
  41. int i, j; //循环迭代变量
  42. int x, y; //用于保存可交换数字对的索引
  43. int maxSum, minSum; //分别用于保存两个数组的数字之和
  44. int diff; //diff = sum1 - sum2
  45. int maxdiff; // 2 * (A[x] - B[y])
  46. int flag; //标记是否找到可交换的数字对
  47. int temp;
  48. int *pMax; //指向数字总和较大的数组
  49. int *pMin; //指向数字总和较小的数组
  50.  
  51. //随机初始化数组
  52. init(A, n1);
  53. init(B, n2);
  54. print(A, n1);
  55. print(B, n2);
  56. //求数组中数字之和
  57. maxSum = sum(A, n1);
  58. minSum = sum(B, n2);
  59.  
  60. if(maxSum == minSum)
  61. {
  62. printf("There is no need to swap!\n");
  63. return ;
  64. }
  65.  
  66. //令pMax和pMin分别指向数字总和大的数组以及总和小的数组
  67. pMax = A;
  68. pMin = B;
  69. if(maxSum < minSum)
  70. {
  71. pMax = B;
  72. pMin = A;
  73. swap(&maxSum, &minSum);
  74. }
  75. //循环交换两个数组中的数字对,在交换的过程中,始终
  76. //保持pMax数组的数字总和大于或者等于pMin数组的数字总和。
  77. //也就是保持diff >= 0
  78. diff = maxSum - minSum;
  79. while()
  80. {
  81. flag = ;
  82. x = y = ;
  83. maxdiff = ;
  84. //寻找能够使diff减小的数字对。
  85. //从趋势上来看,
  86. //减小的幅度越大diff收敛的越快,
  87. //while循环的次数也越少
  88. for(i = ; i < n1; ++i)
  89. {
  90. for(j = ; j < n2; ++j)
  91. {
  92. temp = pMax[i] - pMin[j];
  93. if(temp > && (diff - * temp) >= )
  94. {
  95. if(maxdiff < *temp)
  96. {
  97. maxdiff = * temp;
  98. x = i;
  99. y = j;
  100. flag = ;
  101. }
  102. }
  103. }
  104. }
  105. if(flag) //找到了可以使diff减小的数字对
  106. {
  107. printf("swap, pMax[%d]:%d, pMin[%d]:%d\n", x, pMax[x], y, pMin[y]);
  108. diff -= maxdiff;
  109. swap(pMax + x, pMin + y);
  110. print(A, n1);
  111. print(B, n2);
  112. printf("diff = %d\n", diff);
  113.  
  114. }
  115. else //没有找到可以交换的数字对,终止while循环
  116. {
  117. break;
  118. }
  119. }
  120. return diff; //返回两个数组经交换后的最小差值
  121. }
  122.  
  123. int main(int argc, char **argv)
  124. {
  125.  
  126. srand(time(NULL));
  127. printf("min difference:%d\n", solve(, ));
  128. // system("pause");
  129. // pause();
  130. return ;
  131. }

 4. java实现

  1. import java.util.Arrays;
  2.  
  3. /**
  4. *
  5. * @author Administrator
  6. *
  7. */
  8. public class TestUtil {
  9. private int[] arrysMin = null;
  10.  
  11. private int[] arrysMax = null;
  12.  
  13. private int matchNum = 0;
  14.  
  15. private boolean hasMatched = false;
  16.  
  17. /**
  18. * 返回数组的所有元素的总和
  19. *
  20. * @param arrays
  21. * 待计算数组
  22. * @return 所有元素的总和值
  23. */
  24. public int getArraySum(int[] arrays) {
  25. int sum = 0;
  26. if (null != arrays) {
  27. for (int i : arrays) {
  28. sum += i;
  29. }
  30. }
  31. return sum;
  32. }
  33.  
  34. /**
  35. * 返回数组的差值
  36. *
  37. * @param array1
  38. * 集合一
  39. * @param array2
  40. * 集合二
  41. * @return 差值
  42. */
  43. public int getTowArraysMacth(int[] array1, int[] array2) {
  44. Integer l1 = getArraySum(array1);
  45. Integer l2 = getArraySum(array2);
  46.  
  47. if ((l1 - l2) / 2 > 0) {
  48. arrysMax = array1;
  49. arrysMin = array2;
  50. return (l1 - l2) / 2;
  51. } else {
  52. arrysMax = array2;
  53. arrysMin = array1;
  54. return (l2 - l1) / 2;
  55. }
  56. }
  57.  
  58. private boolean isReturn(int[] arrayMax, int[] arrayMin) {
  59. Integer l1 = getArraySum(arrayMax);
  60. Integer l2 = getArraySum(arrayMin);
  61.  
  62. if ((l1 - l2) > 0) {
  63. return false;
  64. } else {
  65. return true;
  66. }
  67. }
  68.  
  69. public void doMatch() {
  70. // 保证大的数组总和永远是大的,以防递归进入死循环
  71. if (isReturn(arrysMax, arrysMin)) {
  72. return;
  73. }
  74. // 获取元素总和大的与小的差值平均值
  75. int diff = getTowArraysMacth(arrysMax, arrysMin);
  76. // 使用一个大数字初始化最小绝对值,后面做比较
  77. int abs = getArraySum(arrysMax);
  78. int tempElement = 0;
  79. // 最终大数组要交换的下标
  80. int maxIndex = -1;
  81. int minIndex = -1;
  82. if (null != arrysMax && null != arrysMin) {
  83. for (int i = 0; i < arrysMax.length; i++) {
  84. for (int j = 0; j < arrysMin.length; j++) {
  85. int temp = arrysMax[i] - arrysMin[j];
  86. if (temp > 0 && diff > temp) {
  87. // 如果元素差值和元素总和大的与小的差值平均值正好相等,直接交换元素OK
  88. if (Math.abs(diff - temp) == 0) {
  89. tempElement = arrysMin[j];
  90. arrysMin[j] = arrysMax[i];
  91. arrysMax[i] = tempElement;
  92. matchNum++;
  93. hasMatched = true;
  94. return;
  95. } else {
  96. // 否则完全遍历,最终找出元素差值和总和差值平均值差距最小的两元素,
  97. if (abs > Math.abs(diff - temp)) {
  98. abs = Math.abs(diff - temp);
  99. maxIndex = i;
  100. minIndex = j;
  101. }
  102. }
  103. }
  104. }
  105. }
  106. //如果没有找到匹配项,且在已变换的数组中找到了满足条件的变量,则继续递归
  107. if (!hasMatched && (maxIndex != -1 || minIndex != -1)) {
  108. // 交换差距最小的两元素
  109. System.out.printf("第%d次交换, Max[%d]:%d, Min[%d]:%d\n", ++matchNum, maxIndex, arrysMax[maxIndex], minIndex, arrysMin[minIndex]);
  110. tempElement = arrysMin[minIndex];
  111. arrysMin[minIndex] = arrysMax[maxIndex];
  112. arrysMax[maxIndex] = tempElement;
  113. System.out.println("交换后Max数组:" + Arrays.toString(arrysMax));
  114. System.out.println("交换后Min数组:" + Arrays.toString(arrysMin));
  115. System.out.println();
  116. // 递归
  117. doMatch();
  118. }
  119. }
  120. }
  121.  
  122. public int getMatchNum() {
  123. return matchNum;
  124. }
  125.  
  126. /**
  127. * @param args
  128. */
  129. public static void main(String[] args) {
  130. TestUtil tu = new TestUtil();
  131. int[] a1 = { 11, 2, 4, 6, 47 };
  132. int[] a2 = { 4, 5, 8, 9, 2 };
  133. System.out.println("交换前数组a1:" + Arrays.toString(a1));
  134. System.out.println("交换前数组a2:" + Arrays.toString(a2));
  135. // 进行第一次分出,两元素的总和谁大谁小
  136. tu.getTowArraysMacth(a1, a2);
  137. // 开始进行处理交换
  138. tu.doMatch();
  139. // 打印交换结果
  140. System.out.println("交换次数:" + tu.getMatchNum());
  141. System.out.println("a1数组元素和:" + tu.getArraySum(a1));
  142. System.out.println("a2数组元素和:" + tu.getArraySum(a2));
  143. System.out.println("交换后原数组a1:" + Arrays.toString(a1));
  144. System.out.println("交换后原数组a2:" + Arrays.toString(a2));
  145. }
  146. }

参考链接: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. atitit.二维码生成总结java zxing

    atitit.二维码生成总结java zxing #-----zxing类库.. but zxing3.0  的类库core-3.0.jar 需要jdk7 只好zing2.2.jar ..jdk6走o ...

  2. iOS开发-UITextView根据内容自适应高度

    UITextView作为内容文本输入区域,有的时候我们需要根据内容动态改变文本区域的高度,效果如下: 定义UITextView,实现UITextViewDelegate: -(UITextView * ...

  3. 关于eclipse android 在manifest改app应用包名注意事项

    在我刚学android 时候,然后立即就做项目.那时连eclipse 使用都不是很熟练.很多功能都不知道.新手如果这时去改app应用的包名,没有改好会变成所有控件在R文件里面id都找不到. 先上两张图 ...

  4. java匿名对象_面向对象

    class Student{ public void tell(){ System.out.println("Hello jikexueyuan"); } public void ...

  5. eclipse code templates 设置(eclipse注释模版配置)

    文件(Files)注释标签:/** * @Title: ${file_name} * @Package ${package_name} * @Description: ${todo} * Copyri ...

  6. unity 读取excel表 生成asset资源文件

    做unity 项目也有一段时间了,从unity项目开发和学习中也遇到了很多坑,并且也从中学习到了很多曾经未接触的领域.项目中的很多功能模块,从今天开始把自己的思路和代码奉上给学渣们作为一份学习的资料. ...

  7. cygintl-8.dll 是cygwin的哪个包?|Windows查看man手册的方法-cygwin

    答案是: 是 Release\gettext\libintl8\libintl8-0.18.1.1-2.tar.bz2 应该是gettext 项目的一部分吧. 下载地址 可以直接从 cygwin的镜像 ...

  8. CSS等高布局

    做一些后台项目,和一下带侧边栏项目的时候登高布局很常用,总结了下有几种 1.margin-bottom方法 这里直接介绍我认为的最佳的侧边栏/分栏高度自动相等方法.核心的CSS代码如下(数值不固定): ...

  9. 转: sql server2008 字段类型详解

    bit 整型 bit数据类型是整型,其值只能是0.1或空值.这种数据类型用于存储只有两种可能值的数据,如Yes 或No.True 或False .On 或Off. 注意:很省空间的一种数据类型,如果能 ...

  10. Scala 具体的并行集合库【翻译】

    原文地址 本文内容 并行数组(Parallel Array) 并行向量(Parallel Vector) 并行范围(Parallel Range) 并行哈希表(Parallel Hash Tables ...