又是去理解了一次01揹包。
這道題目的意思就是給你乙個n (n < 40)表示有乙個集合
你要將它劃分成相等的兩個子集合,求有幾種劃分方式
如果n是奇數,那麼顯然不能由相同的兩個sub sum組成,所以要輸出「0」
現在我們定義乙個陣列dp[i][j] 表示前i個數組合起來的和是j的種數
接下來就和01揹包很像了
得到狀態轉移方程dp[i][j] = dp[i - 1][j] + dp[i - 1][j - i]
分表代表當前的i 取 和 不取
在每一層 j 的轉移下要倒著來,從(1 + n) * n / 2 / 2開始推到1 (如果是從左到右則會重複計算)
在輸出的時候要把答案除以2因為for every sub sum there're 2 sub sets
至此題目已解決。
source code:
/*id: wushuai2
prog: subset
lang: c++
*///
#pragma comment(linker, "/stack:16777216")
//for c++ compiler
#include #include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define max(a,b) (((a) > (b)) ? (a) : (b))
#define min(a,b) (((a) < (b)) ? (a) : (b))
#define abs(x) (((x) > 0) ? (x) : (-(x)))
#define mod 1000000007
#define pi acos(-1.0)
using
namespace
std;
typedef
long
long
ll ;
typedef unsigned
long
long
ull ;
typedef unsigned
intuint
;typedef unsigned
char
uchar ;
template
inline void checkmin(t &a,t b)
template
inline void checkmax(t &a,t b)
const
double eps = 1e-7
;const
int m = 660000
;const ll p =10000000097ll ;
const
int inf = 0x3f3f3f3f
;const
int max_n = 20
;const
int maxsize = 101000000
;ll f[
2000
];int
main()
max /= 2
; f[
0] = 1
;
for(i = 1; i <= n; ++i)
}fout
<< f[max] / 2
<< endl;//
fin.close();
fout.close();
return0;
}
整數劃分(劃分dp)總結
寫了幾個題發現整數劃分是一類題,而不是一道題。具體題型 1 n相同元素放入m個相同的盤子 盤子允許為空 例題 放蘋果 poj 1664設dp i j 為 j 個元素放入i個盤子轉移方程 dp i j dp i 1 j 新新增乙個盤子,盤子為空 dp i j dp i j i i個盤子 各取出乙個 2...
整數劃分問題
整數劃分問題是乙個經典問題,幾乎在講演算法設計的書中都會講,下面把主要的思想給總結下。所謂整數劃分,就是將乙個正整數n劃分為一系列的正整數之和,如將n可以劃分為 1 我們該如何找出所有的劃分呢?我們可以先來看看整數劃分的規律 譬如正整數 6 劃分情況如下 6 5 14 2 4 1 1 3 3 3 2...
整數劃分問題
給定乙個自然數,分成k部分,a1,a2.的數的和,要求a1 a2.求有多少種?原理 整數n拆分成最多不超過m個數的和的拆分數,和n 拆分成最大不超過m的拆分數相等。根據這個原理,原問題就轉化成了求最大拆分為k的拆分個數與最大拆分為k 1的拆分個數的差 f n,k f n,k 1 f n k,k 如下...