如何交换两个等长整形数组使其数组和的差最小(C和java实现)
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实现)的更多相关文章
- 有两个数组a,b,大小都为n,;通过交换a,b中的元素,使sum(a)-sum(b)最小。
有两个数组a,b,大小都为n,数组元素的值任意整形数,无序: 要求:通过交换a,b中的元素,使数组a元素的和与数组b元素的和之间的差最小. 当前数组a和数组b的和之差为 A = sum(a) - ...
- The Super Powers UVA 11752 分析分析 求无符号长整形以内的数满足至少可以用两种不同的次方来表示。比如64 = 2^6 = 8^2; 一个数的1次方不算数。
/** 题目:The Super Powers UVA 11752 链接:https://vjudge.net/contest/154246#problem/Y 题意:求无符号长整形以内的数满足至少可 ...
- C/C++ 中的0长数组(柔性数组)
转自C/C++ 中的0长数组(柔性数组) 在标准C和C++中0长数组如charArray[0]是不允许使用的,因为这从语义逻辑上看,是完全没有意义的.但是,GUN中却允许使用,而且,很多时候,应用在了 ...
- 实现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 ...
- URAL 1297 最长回文子串(后缀数组)
1297. Palindrome Time limit: 1.0 secondMemory limit: 64 MB The “U.S. Robots” HQ has just received a ...
- 编程技巧:使用异或操作符(XOR)交换两数值
异或(exclusive OR)作为4种逻辑操作符之一,相对其他3种(OR/AND/NOT)来说,出场的次数非常少,是因为在日常开发中能用到它的场景本来就不多.对笔者来说,目前接触到场景只有交换两个数 ...
- 面试题-JavaScript交换两个变量的方法
在平时的业务开发或者面试过程中,经常会遇到交换两个变量这种问题,于是,个人总结以下几种交换变量的方法: 1.方案一 使用一个临时变量来交换 2.方案二 使用ES6解构赋值语法来交换 3.方案三利用数 ...
- Java 交换两数的方法
错误示范 1. 直接交换 public class SwapNumbers { // 直接交换 public static void swap(int a, int b) { int temp = a ...
- (持续更新)虚树,KD-Tree,长链剖分,后缀数组,后缀自动机
真的就是讲课两天,吸收一个月呢! \(1.\)虚树 \(2.\)KD-Tree \(3.\)长链剖分 \(4.\)后缀数组 后缀数组 \(5.\)后缀自动机 后缀自动机
随机推荐
- atitit.二维码生成总结java zxing
atitit.二维码生成总结java zxing #-----zxing类库.. but zxing3.0 的类库core-3.0.jar 需要jdk7 只好zing2.2.jar ..jdk6走o ...
- iOS开发-UITextView根据内容自适应高度
UITextView作为内容文本输入区域,有的时候我们需要根据内容动态改变文本区域的高度,效果如下: 定义UITextView,实现UITextViewDelegate: -(UITextView * ...
- 关于eclipse android 在manifest改app应用包名注意事项
在我刚学android 时候,然后立即就做项目.那时连eclipse 使用都不是很熟练.很多功能都不知道.新手如果这时去改app应用的包名,没有改好会变成所有控件在R文件里面id都找不到. 先上两张图 ...
- java匿名对象_面向对象
class Student{ public void tell(){ System.out.println("Hello jikexueyuan"); } public void ...
- eclipse code templates 设置(eclipse注释模版配置)
文件(Files)注释标签:/** * @Title: ${file_name} * @Package ${package_name} * @Description: ${todo} * Copyri ...
- unity 读取excel表 生成asset资源文件
做unity 项目也有一段时间了,从unity项目开发和学习中也遇到了很多坑,并且也从中学习到了很多曾经未接触的领域.项目中的很多功能模块,从今天开始把自己的思路和代码奉上给学渣们作为一份学习的资料. ...
- cygintl-8.dll 是cygwin的哪个包?|Windows查看man手册的方法-cygwin
答案是: 是 Release\gettext\libintl8\libintl8-0.18.1.1-2.tar.bz2 应该是gettext 项目的一部分吧. 下载地址 可以直接从 cygwin的镜像 ...
- CSS等高布局
做一些后台项目,和一下带侧边栏项目的时候登高布局很常用,总结了下有几种 1.margin-bottom方法 这里直接介绍我认为的最佳的侧边栏/分栏高度自动相等方法.核心的CSS代码如下(数值不固定): ...
- 转: sql server2008 字段类型详解
bit 整型 bit数据类型是整型,其值只能是0.1或空值.这种数据类型用于存储只有两种可能值的数据,如Yes 或No.True 或False .On 或Off. 注意:很省空间的一种数据类型,如果能 ...
- Scala 具体的并行集合库【翻译】
原文地址 本文内容 并行数组(Parallel Array) 并行向量(Parallel Vector) 并行范围(Parallel Range) 并行哈希表(Parallel Hash Tables ...