首页 > 代码库 > 几个相似的DP题

几个相似的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;
    
}

 继续努力吧!!

  

几个相似的DP题