【題目】
任意2n個正整數,從其中選出n個整數,使得選出的n個整數和同剩下的n個整數之和的差最小。
【**】 網易
【分析】
假設陣列a[1..2n]所有元素的和是sum。模仿動態規劃解0-1揹包問題的策略。
從2n個數中找n個元素,有三種可能:大於sum/2,小於sum/2以及等於sum/2。而大於sum/2與小於等於sum/2沒區別,故可以只考慮小於等於sum/2的情況。
令s(k, i)表示前k個元素中任意i個元素的和的集合。顯然:
s(k, 1) =
s(k, k) =
s(k, i) = s(k-1, i) u
按照這個遞推公式來計算,最後找出集合s(2n, n)中與sum/2最接近的那個和,這便是答案。
【分析一】
狀態轉移方程:
其中,s[i-1][j][k]表示前i-1個元素中選取j個使其和不超過但最逼近k;
s[i-1][j-1][k-a[i]]在前i-1個元素中選取j-1個元素使其和不超過但最逼近k-a[i],這樣再加上a[i]即第i個元素就變成了 選擇上第i個元素的情況下最逼近k的和。
而第一種情況與第二種情況是完備且互斥的,所以需要將兩者最大的值作為f[i][j][k]的值。
可以設定乙個三維陣列path來記錄所選擇元素的軌跡。根據求得的path我們可以從s[2n][n][sum/2]往s[0][0][0]逆著推導來列印軌跡對應的元素。
該演算法的時間複雜度為o(n^2*sum),空間複雜度也為o(n^2*sum)。
【**一】
/*********************************
* 日期:2015-02-01
* 題目: 陣列分割
* 部落格:
**********************************/
#include #include #include using namespace std;
// 模仿動態規劃解0-1揹包問題的策略
int minsum(int num,int n)//if
int sum = 0;
int size = 2*n;
// the sum of all number
for(int i = 1;i <= size;++i)//for
int dp[size + 1][n + 1][sum / 2 + 1];
// 選中數字路徑
int path[size + 1][n + 1][sum / 2 + 1];
memset(dp,0,sizeof(dp));
memset(path,0,sizeof(path));
// 用dp(i,j,k)來表示從前i個元素中取j個元素,使得其和不超過k且最接近k,j <= min(i,n),k <= sum/2
// 狀態轉移方程:
// dp(i,j,k)= max
// dp(2n,n,sum/2+1)就是題目的解。
// 前i個元素
for(int i = 1;i <= size;++i)//if
}//for
}//for
}//for
// 列印選擇路徑
int i = 2*n,j = n,k = sum / 2;
while(i > 0 && j > 0, k > 0)//if
int sum = 0;
int size = 2*n;
// the sum of all number
for(int i = 1;i <= size;++i)//for
int dp[n + 1][sum / 2 + 1];
// 選中數字路徑
int path[size+1][n + 1][sum / 2 + 1];
memset(dp,0,sizeof(dp));
memset(path,0,sizeof(path));
//for(int i = 1;i <= size;++i)//if
}//for
}//for
}//for
// 列印選擇路徑
int i = 2 * n,j = n,k = sum / 2;
while(i > 0 && j > 0 && k > 0)//if
int sum = 0;
int size = 2*n;
// the sum of all number
for(int i = 1;i <= size;++i)//for
// isok[i][v]表示是否可以找到i個數,使得它們之和等於v
int isok[n + 1][sum / 2 + 1];
int path[size + 1][n + 1][sum / 2 + 1];
// 都不合法
memset(isok,0,sizeof(isok));
memset(path,0,sizeof(path));
// 注意初始化
// 可以,取0件物品,總合為0,是合法的
isok[0][0] = 1;
for(int i = 1;i <= size;++i)//if
}//for
}//for
}//for
// 列印選擇路徑
int i = 2 * n,j = n,k = sum / 2;
while(i > 0 && j > 0 && k > 0)//if
}//for
int sum1 = minnum;
int sum2 = sum - minnum;
cout
經典面試題
1.以下三條輸出語句分別輸出什麼?char str1 abc char str2 abc const char str3 abc const char str4 abc const char str5 abc const char str6 abc cout boolalpha str1 str2 ...
經典面試題
我的老同學現在富得流油。他開創了乙個軟體公司,開發了一系列軟體,生意越做越大。今天他來到這個城市後馬上打 給我。是我啊!聽出來了嗎?是這樣的,我到這兒的大學招畢業生,要在這兒呆上五天,咱哥們趁這個時間好好聚一聚。我做東!既然他要做東,我理所當然順水推舟。人家是老闆,不吃白不吃!我來到他下榻的賓館,看...
經典面試題
分兩個情況 perfork模式 worker模式 前者程序模式 後者執行緒模式 故檢視方法也有區別 oldboy.log 參考 分析 此類問題是運維工作中最常見的問題。可以演變成分析日誌,檢視tcp各個狀態連線數,檢視單ip連線數排名等等 第一類 過濾網域名稱方法 方法很多 這裡給出六種為例。還可以...