今天又看见了这个题目,好像上次是李灾跟我说腾讯面他的时候问了这个问题的。想了半天,在网上也看了半天,发现一个不错的算法,先帖出来:^ ^
/*
有两个数组a,b,大小都为n,数组元素的值任意整形数,无序;
要求:通过交换a,b中的元素,使[数组a元素的和]与[数组b元素的和]之间的差最小。
*/
/*
求解思路:
当前数组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'| = |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为止。
*/
把算法大概实现了一下,程序如下:
1
int
test(
float
a[],
float
b[],
int
n)
2
{
3
float
sumA, sumB;
//
sumA为数组a总和,sumB为数组b总和
4
float
sum_diff, num_diff;
//
sum_diff为a,b总和差, num_diff为a,b中各选的两个数之差
5
float
temp1, temp2;
//
temp1为 每轮sum_diff/2, temp2为每轮所选两个数之差于temp1最接近的那个
6
int
i, j;
7
float
temp;
//
用于对调a,b间数
8
int
tempi, tempj;
//
每轮所选两个数之差于temp1最接近的那组数
9
unsigned
int
flag_sum
=
0
, flag_num
=
0
;
//
flag_sum为1, sumA大于sumB; flag_num为1, 此轮存在两个数之差小于sum_diff
10
11
12
13
14
while
(
1
){
15
16
//
算出a,b数组和
17
sumA
=
0
;
18
sumB
=
0
;
19
for
(i
=
0
;i
<
n;i
++
)
20
{
21
sumA
+=
a[i];
22
sumB
+=
b[i];
23
}
24
25
if
(sumA
>=
sumB){
26
sum_diff
=
sumA
-
sumB;
27
flag_sum
=
1
;
28
}
29
else
30
sum_diff
=
sumB
-
sumA;
31
32
temp1
=
sum_diff
/
2
;
33
temp2
=
temp1;
34
tempi
=
0
;
35
tempj
=
0
;
36
37
//
找出a,b间差值最接近sum_diff/2的那一对数
38
if
(flag_sum
==
1
){
//
sumA > sumB
39
for
(i
=
0
; i
<
n; i
++
)
40
for
(j
=
0
; j
<
n; j
++
)
41
42
if
(a[i]
>
b[j]){
43
num_diff
=
a[i]
-
b[j];
44
if
(num_diff
<
sum_diff){
45
flag_num
=
1
;
46
if
(num_diff
>=
temp1){
47
if
(num_diff
-
temp1
<
temp2){
48
temp2
=
num_diff
-
temp1;
49
tempi
=
i;
50
tempj
=
j;
51
}
52
}
53
else
{
54
if
(temp1
-
num_diff
<
temp2){
55
temp2
=
temp1
-
num_diff;
56
tempi
=
i;
57
tempj
=
j;
58
}
59
}
60
}
61
}
62
}
63
else
{
64
for
(i
=
0
; i
<
n; i
++
)
65
for
(j
=
0
; j
<
n; j
++
)
66
67
if
(a[i]
<
b[j]){
68
num_diff
=
b[j]
-
a[i];
69
if
(num_diff
<
sum_diff){
70
flag_num
=
1
;
71
if
(num_diff
>=
temp1){
72
if
(num_diff
-
temp1
<
temp2){
73
temp2
=
num_diff
-
temp1;
74
tempi
=
i;
75
tempj
=
j;
76
}
77
}
78
else
{
79
if
(temp1
-
num_diff
<
temp2){
80
temp2
=
temp1
-
num_diff;
81
tempi
=
i;
82
tempj
=
j;
83
}
84
}
85
}
86
}
87
}
88
89
if
(flag_num
==
0
)
90
break
;
91
92
temp
=
a[tempi];
93
a[tempi]
=
b[tempj];
94
b[tempj]
=
temp;
95
96
flag_num
=
0
;
97
flag_sum
=
0
;
98
}
99
100
for
(i
=
0
; i
<
n;i
++
)
101
printf(
"
%f/t
"
,a[i]);
102
103
printf(
"
/n
"
);
104
105
for
(i
=
0
; i
<
n;i
++
)
106
printf(
"
%f/t
"
,b[i]);
107
108
printf(
"
/n
"
);
109
110
return
0
;
111
}
112
113
114
int
main(
int
argc,
char
*
argv[])
115
{
116
117
float
a[
3
]
=
{
4
,
5
,
12
};
118
float
b[
3
]
=
{
1
,
2
,
3
};
119
120
test(a, b,
3
);
121
122
return
0
;
123
}
124