プログラミングの美2.18配列分割
8586 ワード
本明細書から:http://www.cnblogs.com/freewater/archive/2012/08/23/2652974.html
問題の説明:
ソートされていない要素の数が2 Nの正の整数配列があります.要素個数Nの2つの配列に分割し,2つのサブ配列の和を最も近づけることが要求される.
問題解決の考え方:
配列A[1.2 N]のすべての要素の和がSUMであると仮定する.動的計画解0−1リュック問題の戦略を模倣し,S(k,i)に前のk要素のうち任意のi要素の和の集合を表す.明らかに,S(k,1)={A[i]|1<=i<=k}S(k,k)={A[1]+A[2]+…+A[k]}S(k,i)=S(k−1,i)U{A[k]+x|xはS(k−1,i−1)}この繰返し式に従って計算し,最後に集合S(2 N,N)の中でSUMに最も近いその和を探し出すことが答えである.このアルゴリズムの時間的複雑さはO(2^N)である.この過程でSUM/2以下のサブ配列の和のみに注目し,大きくないからである.したがって,集合中の和がSUM/2より大きい和は意味がない.これらの意味のない和を除いて、残りの意味のある和の個数はSUM/2個までです.したがって,S(2 N,N)にどのような和があるかを記録する必要はなく,SUM/2から1まで1回遍歴し,この値がS(2 N,N)に現れるかどうかを1つずつ尋ね,最初に現れる値が答えである.我々のプログラムでは,上記の繰返し式に従って各集合を計算する必要はなく,各集合にフラグ配列を設け,SUM/2から1という区間のどの値をマークして計算できるかを示す必要がある.
コード:
問題の説明:
ソートされていない要素の数が2 Nの正の整数配列があります.要素個数Nの2つの配列に分割し,2つのサブ配列の和を最も近づけることが要求される.
問題解決の考え方:
配列A[1.2 N]のすべての要素の和がSUMであると仮定する.動的計画解0−1リュック問題の戦略を模倣し,S(k,i)に前のk要素のうち任意のi要素の和の集合を表す.明らかに,S(k,1)={A[i]|1<=i<=k}S(k,k)={A[1]+A[2]+…+A[k]}S(k,i)=S(k−1,i)U{A[k]+x|xはS(k−1,i−1)}この繰返し式に従って計算し,最後に集合S(2 N,N)の中でSUMに最も近いその和を探し出すことが答えである.このアルゴリズムの時間的複雑さはO(2^N)である.この過程でSUM/2以下のサブ配列の和のみに注目し,大きくないからである.したがって,集合中の和がSUM/2より大きい和は意味がない.これらの意味のない和を除いて、残りの意味のある和の個数はSUM/2個までです.したがって,S(2 N,N)にどのような和があるかを記録する必要はなく,SUM/2から1まで1回遍歴し,この値がS(2 N,N)に現れるかどうかを1つずつ尋ね,最初に現れる値が答えである.我々のプログラムでは,上記の繰返し式に従って各集合を計算する必要はなく,各集合にフラグ配列を設け,SUM/2から1という区間のどの値をマークして計算できるかを示す必要がある.
コード:
1 #include<iostream>
2 using namespace std;
3
4 int arr[] = {0,1,5,7,8,9,6,3,11,20,17};
5 const int N = 5;
6 const int Sum = 87;
7
8 // 0-1
9 int solve1()
10 {
11 int i, j, s;
12 int dp[2*N+1][N+1][Sum/2+2];
13 /*
14 dp(i,j,c) i j 、 j c ( ) , i>=j,c<=S
15 :
16 i
17 dp(i,j,c)=max{dp(i-1,j-1,c-a[i])+a[i],dp(i-1,j,c)}
18 dp(2N,N,SUM/2+1) 。
19 */
20 //
21 memset(dp,0,sizeof(dp));
22 for(i = 1 ; i <= 2*N ; ++i)
23 {
24 for(j = 1 ; j <= min(i,N) ; ++j)
25 {
26 for(s = Sum/2+1 ; s >= arr[i] ; --s)
27 {
28 dp[i][j][s] = max(dp[i-1][j-1][s-arr[i]]+arr[i] , dp[i-1][j][s]);
29 }
30 }
31 }
32
33 // dp[2*N][N][SUM/2+1];
34 i=2*N , j=N , s=Sum/2+1;
35 while(i > 0)
36 {
37 if(dp[i][j][s] == dp[i-1][j-1][s-arr[i]]+arr[i]) //
38 {
39 cout<<arr[i]<<" "; // arr[i]
40 j--;
41 s -= arr[i];
42 }
43 i--;
44 }
45 cout<<endl;
46 return dp[2*N][N][Sum/2+1];
47 }
48
49 int main(void)
50 {
51 int s1 = solve1();
52 cout<<"s1="<<s1<<endl;
53 return 0;
54 }