如何交换两个等长整形数组使其数组和的差最小(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.\)后缀自动机 后缀自动机
随机推荐
- JS基本内容
js是网页的脚本语言,它也是有内嵌和外部两种,样式是写在头部,脚本语言可以写在任何位置,通常写在网页底部:<script type="texe/javascript"> ...
- R 报错:package ‘***’ is not available (for R version ****) 的解决方案
R 安装sparklyr,ggplot2等包出现如下warning package '****' is not available (for R version 3.0.2) 系统环境 ubuntu1 ...
- 用自己的算法实现startsWith和endsWith功能
package hanqi; import java.util.Random; import java.util.Scanner; public class zuoye { public static ...
- python中xrange和yield的用法
相信很多人对xrange和yield都不是很清楚,网上很多文章也是写的云里雾里的,今天我用最简单的例子给大家说下. 说起xrange的时候就一定要提range,其实xrange 用法与 range 完 ...
- MyEclipse xml 手动添加 dtd
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "- ...
- LPC43XX JTAG Scan Chain
Debug and trace functions are integrated into the ARM Cortex-M4. Serial wire debug and trace functio ...
- Web app 的性能瓶颈与性能调优方法
1. web app 性能测试工具使用 2. mysql 性能分析与调优方法
- 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 ...
- centos 7 /etc/rc.local 开机不执行的问题
最近发现centos7 的/etc/rc.local不会开机执行,于是认真看了下/etc/rc.local文件内容的就发现了问题的原因了 1 2 3 4 5 6 7 8 9 10 11 #!/bin/ ...
- 如何修改 EM12c 中 SYSMAN 用户的密码?
以下内容全部转自:http://www.chenjunlu.com/2013/04/how-to-modify-the-password-for-sysman-of-em-12c-cloud-cont ...