1+ package class12 ;
2+
3+ import java .util .TreeSet ;
4+
5+ /*
6+ * 给定一个整型数组arr,请把arr中所有的数分成两个集合
7+ * 如果arr长度为偶数,两个集合包含数的个数要一样多
8+ * 如果arr长度为奇数,两个集合包含数的个数必须只差一个
9+ * 请尽量让两个集合的累加和接近
10+ * 返回最接近的情况下,较小集合的累加和(较大集合的累加和一定是所有数累加和减去较小集合的累加和)
11+ * 为了方便起见,假设arr中没有负数,其实也可以有
12+ * 但是处理起来会比较麻烦,而且有没有负数都不影响算法流程的理解
13+ * */
14+ public class Code11_SplitSumClosedSizeHalf {
15+
16+ public static int right (int [] arr ) {
17+ if (arr == null || arr .length < 2 ) {
18+ return 0 ;
19+ }
20+ int sum = 0 ;
21+ for (int num : arr ) {
22+ sum += num ;
23+ }
24+ TreeSet <Integer > ans = new TreeSet <>();
25+ process (arr , 0 , 0 , 0 , ans , sum >> 1 );
26+ return ans .last ();
27+ }
28+
29+ public static void process (int [] arr , int i , int sum , int picks , TreeSet <Integer > ans , int limit ) {
30+ if (i == arr .length ) {
31+ if ((arr .length & 1 ) == 0 ) {
32+ if (picks == (arr .length >> 1 ) && sum <= limit ) {
33+ ans .add (sum );
34+ }
35+ } else {
36+ if ((picks == (arr .length >> 1 ) || picks == (arr .length >> 1 ) + 1 ) && sum <= limit ) {
37+ ans .add (sum );
38+ }
39+ }
40+ } else {
41+ process (arr , i + 1 , sum , picks , ans , limit );
42+ process (arr , i + 1 , sum + arr [i ], picks + 1 , ans , limit );
43+ }
44+ }
45+
46+ public static int dp (int [] arr ) {
47+ if (arr == null || arr .length < 2 ) {
48+ return 0 ;
49+ }
50+ int sum = 0 ;
51+ for (int num : arr ) {
52+ sum += num ;
53+ }
54+ sum >>= 1 ;
55+ int N = arr .length ;
56+ int M = (arr .length + 1 ) >> 1 ;
57+ int [][][] dp = new int [N ][M + 1 ][sum + 1 ];
58+ for (int i = 0 ; i < N ; i ++) {
59+ for (int j = 0 ; j <= M ; j ++) {
60+ for (int k = 0 ; k <= sum ; k ++) {
61+ dp [i ][j ][k ] = Integer .MIN_VALUE ;
62+ }
63+ }
64+ }
65+ for (int i = 0 ; i < N ; i ++) {
66+ for (int k = 0 ; k <= sum ; k ++) {
67+ dp [i ][0 ][k ] = 0 ;
68+ }
69+ }
70+ for (int k = 0 ; k <= sum ; k ++) {
71+ dp [0 ][1 ][k ] = arr [0 ] <= k ? arr [0 ] : Integer .MIN_VALUE ;
72+ }
73+ for (int i = 1 ; i < N ; i ++) {
74+ for (int j = 1 ; j <= Math .min (i + 1 , M ); j ++) {
75+ for (int k = 0 ; k <= sum ; k ++) {
76+ dp [i ][j ][k ] = dp [i - 1 ][j ][k ];
77+ if (k - arr [i ] >= 0 ) {
78+ dp [i ][j ][k ] = Math .max (dp [i ][j ][k ], dp [i - 1 ][j - 1 ][k - arr [i ]] + arr [i ]);
79+ }
80+ }
81+ }
82+ }
83+ return Math .max (dp [N - 1 ][M ][sum ], dp [N - 1 ][N - M ][sum ]);
84+ }
85+
86+ public static int [] randomArray (int len , int value ) {
87+ int [] arr = new int [len ];
88+ for (int i = 0 ; i < arr .length ; i ++) {
89+ arr [i ] = (int ) (Math .random () * value );
90+ }
91+ return arr ;
92+ }
93+
94+ public static void printArray (int [] arr ) {
95+ for (int num : arr ) {
96+ System .out .print (num + " " );
97+ }
98+ System .out .println ();
99+ }
100+
101+ public static void main (String [] args ) {
102+ int maxLen = 20 ;
103+ int maxValue = 50 ;
104+ int testTime = 10000 ;
105+ System .out .println ("测试开始" );
106+ for (int i = 0 ; i < testTime ; i ++) {
107+ int len = (int ) (Math .random () * maxLen );
108+ int [] arr = randomArray (len , maxValue );
109+ int ans1 = right (arr );
110+ int ans2 = dp (arr );
111+ if (ans1 != ans2 ) {
112+ printArray (arr );
113+ System .out .println (ans1 );
114+ System .out .println (ans2 );
115+ System .out .println ("Oops!" );
116+ break ;
117+ }
118+ }
119+ System .out .println ("测试结束" );
120+ }
121+
122+ }
0 commit comments