几个相似的DP题
HDU1398
题意:把一个整数分拆成1、4、9、16、……、256、289(注意:只到289)这17个完全平方数的和,有几种方法。
解法不用说自然是DP,因为搜索显然超时。
(这样的题我一般不敢开int,怕爆……)
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #include <functional> 6 7 using namespace std; 8 9 #define REP(i,n) for(int i(0); i < (n); ++i) 10 #define rep(i,a,b) for(int i(a); i <= (b); ++i) 11 #define dec(i,a,b) for(int i(a); i >= (b); --i) 12 #define for_edge(i,x) for(int i = H[x]; i; i = X[i]) 13 14 #define LL long long 15 #define ULL unsigned long long 16 #define MP make_pair 17 #define PB push_back 18 #define FI first 19 #define SE second 20 #define INF 1 << 30 21 22 const int N = 100000 + 10; 23 const int M = 10000 + 10; 24 const int Q = 1000 + 10; 25 const int A = 30 + 1; 26 27 LL f[Q]; 28 int n; 29 30 31 int main(){ 32 #ifndef ONLINE_JUDGE 33 freopen("test.txt", "r", stdin); 34 freopen("test.out", "w", stdout); 35 #endif 36 37 38 memset(f, 0, sizeof f); 39 f[0] = 1LL; 40 rep(i, 1, 17) rep(j, 0, 305) 41 f[j + i * i] += f[j]; 42 43 while (~scanf("%d", &n), n) printf("%lld\n", f[n]); 44 45 46 return 0; 47 48 }
HDU1028 自然数无序拆分
恩,经典的DP题
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #include <functional> 6 7 using namespace std; 8 9 #define REP(i,n) for (int i(0); i < (n); ++i) 10 #define rep(i, a, b) for (int i(a); i <= (b); ++i) 11 #define dec(i, a, b) for (int i(a); i >= (b); --i) 12 13 #define LL long long 14 #define ULL unsigned long long 15 #define MP make_pair 16 #define FI first 17 #define SE second 18 19 const int INF = 1000000; 20 const int M = 10000 + 10; 21 const int N = 200 + 10; 22 const int A = 3000 + 1; 23 24 25 int f[N][N]; 26 int n; 27 28 int main(){ 29 freopen("1test.in", "r", stdin); 30 freopen("1test.out", "w", stdout); 31 32 rep(i, 1, 150) f[1][i] = 1, f[i][1] = 1; 33 rep(i, 1, 150) rep(j, 1, 150){ 34 if (j > i) f[i][j] = f[i][i]; else 35 if (i == j) f[i][j] = f[i][j - 1] + 1; else 36 f[i][j] = f[i][j - 1] + f[i - j][j]; 37 } 38 39 while (~scanf("%d ", &n)) printf("%d\n", f[n][n]); 40 41 return 0; 42 43 }
二维的方法……但是我以前用一维的方法AC过,总觉得该回忆起来……
HDU5890 去掉给定编号的三个数(如果有编号重复那就相当于去掉了两个数甚至一个数)任意选10个数,相加,是否可以得到87?
当初青岛网赛的题,题意不难理解就是A不掉。
后来查了很多资料,并且看了很多巨屌的博客。我终于得出一个结论:此题要用bitset优化。
思想也是背包,但是和前两道比起来就比较复杂了。
#include <bitset> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define rep(i,a,b) for(int i(a); i <= (b); ++i) #define dec(i,a,b) for(int i(a); i >= (b); --i) const int N = 50 + 2; int T; int q; int f[N][N][N]; int n; int c[5]; int a[N]; int Q; bitset <90> A[12]; int check(int i, int j, int k){ rep(h, 0, 10) A[h].reset(); A[0][0] = 1; rep(h, 1, n) if (h != i && h != j && h != k && a[h] <= 87) dec(p, 9, 0){ A[p + 1] |= A[p] << a[h]; if (A[10][87]) return 1; } return 0; } int main(){ #ifndef ONLINE_JUDGE freopen("test.txt", "r", stdin); freopen("test.out", "w", stdout); #endif scanf("%d", &T); while (T--){ scanf("%d", &n); rep(i, 1, n) scanf("%d", a + i); rep(i, 1, n) rep(j, i, n) rep(k, j, n) f[i][j][k] = check(i, j, k); scanf("%d", &Q); while (Q--){ scanf("%d%d%d", c + 1, c + 2, c + 3); sort(c + 1, c + 4); puts(f[c[1]][c[2]][c[3]] ? "Yes" : "No"); } } return 0; }
继续努力吧!!