动态规划

1、经典问题:(数塔)自顶向下分析,自底向上计算

poj3176Cow Bowling

View Code
#include <iostream>
#include <cmath>
using namespace std;

int a[355][355], dp[355][355];
int n;

int main()
{
    while(cin >> n) {
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= i; j++) {
                cin >> a[i][j];
            }
        }

        for(int i = 1; i <= n; i++)
            dp[n][i] = a[n][i];

        for(int i = n-1; i >= 1; i--) {
            for(int j = 1; j <= i; j++) {
                dp[i][j] = a[i][j] + max(dp[i+1][j], dp[i+1][j+1]);
            }
        }
        cout << dp[1][1] << endl;
    }
    return 0;
}

2、最长有序(递增或递减)序列

核心算法:

for(int i = 1; i <= n; i++) {
            maxtemp = 0;
            for(int j = 1; j <= i; j++) {
                if(a[j] < a[i] && maxtemp < dp[j])
                    maxtemp = dp[j];
            }
            dp[i] = maxtemp+1;
}

例题:

1)、poj2533Longest Ordered Subsequence

View Code
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;

int main()
{
    int n;
    int a[1100], dp[1100];

    while(cin >> n) {
        for(int i = 1; i <= n; i++)
            cin >> a[i];

        int len = 0;
        int maxtemp;

        for(int i = 1; i <= n; i++) {
            dp[i] = 1;
            maxtemp = 0;
            for(int j = 1; j <= i; j++) {
                if(a[j] < a[i] && maxtemp < dp[j])
                    maxtemp = dp[j];
            }
            dp[i] = maxtemp+1;
            if(len < dp[i])
                len = dp[i];
        }
        cout << len << endl;
    }
    return 0;
}

----------------------------------------------------------------------

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;

int main()
{
    int n;
    int a[1100], dp[1100];

    while(cin >> n) {
        for(int i = 1; i <= n; i++)
            cin >> a[i];

        int len = 0;
        for(int i = 1; i <= n; i++) {
            dp[i] = 1;
            for(int j = 1; j <= i; j++) {
                if(a[j] < a[i] && dp[i] < dp[j]+1)
                    dp[i] = dp[j]+1;
            }
            if(len < dp[i])
                len = dp[i];
        }
        cout << len << endl;
    }
    return 0;
}

2)、poj1836Alignment

View Code
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>
using namespace std;

int main()
{
    int n;
    double a[1001];
    int dp[1001], opt[1001];

    while(cin >> n) {

        for(int i = 1; i <= n; i++)
            cin >> a[i];

        dp[1] = 1;
        int maxtemp;

        for(int i = 2; i <= n; i++) {
            maxtemp = 0;
            for(int j = 1; j < i; j++) {
                if(a[i] > a[j] && maxtemp < dp[j])
                    maxtemp = dp[j];
            }
            dp[i] = maxtemp + 1;
        }

        opt[n] = 1;
        for(int i = n-1; i >= 1; i--) {
            maxtemp = 0;
            for(int j = n; j > i; j--) {
                if(a[i] > a[j]&&maxtemp < opt[j]) {
                    maxtemp = opt[j];
                }
            }
            opt[i] = maxtemp+1;
        }

        int maxn = 0;
        for(int i = 1; i <= n; i++) {
            for(int j = i+1; j <= n; j++) {
                if(maxn < dp[i] + opt[j])
                    maxn = dp[i] + opt[j];
            }
        }
        cout << n-maxn << endl;
    }
    return 0;
}

3、最长公共子序列

核心算法

for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= n; j++) {
            dp[i][j] = max(dp[i][j-1], dp[i-1][j]);
            if(a[i] == b[j]) {
                dp[i][j] = max(dp[i][j], dp[i-1][j-1]+1);
            }
        }
}

poj1159Palindrome

View Code
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#define max(a,b) (a>b?a:b)
using namespace std;

short int dp[5001][5001];


int main()
{
    int n;
    int a[5001], b[5001];
    char str;
    
    cin >> n;
    getchar();
    for(int i = 1; i <= n; i++) {
        scanf("%c", &str);
        a[i] = str;
        b[n-i+1] = str;
    }
    for(int i = 0; i <= n; i++) {
        dp[i][0] = 0;
        dp[0][i] = 0;
    }
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= n; j++) {
            dp[i][j] = max(dp[i][j-1], dp[i-1][j]);
            if(a[i] == b[j]) {
                dp[i][j] = max(dp[i][j], dp[i-1][j-1]+1);
            }
        }
    }
    int maxn = dp[n][n];
    printf("%d\n", n-maxn);

    return 0;
}

此题还要注意short int 数组的运用

short int 为2字节  int为4字节  使用short int 可以节省空间

4、形如 E[i,j]=opt{D[i-1,j]+xi,D[i,j-1]+yj,D[i-1][j-1]+zij}

poj1080Human Gene Functions

View Code
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#define INF 999999999
using namespace std;

int g['T'+1]['T'+1];
int dp[110][110];

void init() {
    g['A']['A'] = 5;
    g['C']['C'] = 5;
    g['G']['G'] = 5;
    g['T']['T'] = 5;
    g['-']['-'] = INF;
    g['A']['C'] = g['C']['A'] = -1;
    g['A']['G'] = g['G']['A'] = -2;
    g['A']['T'] = g['T']['A'] = -1;
    g['A']['-'] = g['-']['A'] = -3;
    g['C']['G'] = g['G']['C'] = -3;
    g['C']['T'] = g['T']['C'] = -2;
    g['C']['-'] = g['-']['C'] = -4;
    g['G']['T'] = g['T']['G'] = -2;
    g['G']['-'] = g['-']['G'] = -2;
    g['T']['-'] = g['-']['T'] = -1;
    return;
}

int  maxn(int a, int b, int c) {
    int temp = max(a, b);
    temp = max(temp, c);
    return temp;
}

int main()
{
    int T;
    int lena, lenb;
    char s2[110], s1[110];

    cin >> T;
    while(T--) {
        init();
        cin >> lena;
        cin >> s1;
        cin >> lenb;
        cin >> s2;

        dp[0][0] = 0;

        for(int i = 1; i <= lena; i++)
            dp[i][0] = dp[i-1][0] + g[s1[i-1]]['-'];

        for(int i = 1; i <= lenb; i++)
            dp[0][i] = dp[0][i-1] + g['-'][s2[i-1]];

        for(int i = 1; i <= lena; i++) {
            for(int j = 1; j <= lenb; j++) {
                int temp1 = dp[i-1][j] + g[s1[i-1]]['-'];
                int temp2 = dp[i][j-1] + g['-'][s2[j-1]];
                int temp3 = dp[i-1][j-1] + g[s1[i-1]][s2[j-1]];
                dp[i][j] = maxn(temp1, temp2, temp3);
            }
        }
        cout << dp[lena][lenb] << endl;
    }
    return 0;
}

5、形如 E[j]=opt{D+w(i,j)}

1)、poj1260Pearls

View Code
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;

int main()
{
    int T;
    cin >> T;
    while(T--) {
        int n;
        cin >> n;
        int *a = new int[n+1];
        int *p = new int[n+1];
        int *dp = new int[n+1];
        int *sum = new int[n+1];

        sum[0] = 0;

        for(int i = 1; i <= n; i++) {
            cin >> a[i] >> p[i];
            sum[i] = sum[i-1] + a[i];
        }

        dp[0] = 0;
        for(int i = 1; i <= n; i++) {
            dp[i] = (a[i]+ 10)*p[i] + dp[i-1];
            for(int j = 0; j < i; j++) {
                dp[i] = min(dp[i], dp[j] + (sum[i]-sum[j]+10)*p[i]);
            }
        }
        cout << dp[n] << endl;
        delete a, p, dp, sum;
    }
    return 0;
}

2)、poj3267The Cow Lexicon

View Code
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
using namespace std;

int main()
{
    int W,L;

    while(cin >> W >> L) {
        int* dp = new int[L+1];
        char* str = new char[L+1];
        string* s = new string[W];
        cin >> str;
        for(int i = 0; i < W; i++)
            cin >> s[i];

        dp[L] = 0;

        for(int i = L-1; i >= 0; i--) {
            dp[i] = dp[i+1] + 1;

            for(int j = 0; j < W; j++) {
                int len = s[j].length();
                if(len <= L-i && s[j][0] == str[i]) {
                    int pm = i;
                    int pd = 0;
                    while(pm < L) {
                        if(s[j][pd] == str[pm++])
                            pd++;
                        if(pd == len) {
                            dp[i] = min(dp[i], dp[pm]+(pm-i)-len);
                            break;
                        }
                    }
                }
            }
        }

        cout << dp[0] << endl;
    }
    return 0;
}

注意:数组的开法

int* dp = new int[L+1];
char* str = new char[L+1];
string* s = new string[W];

在poj上提交时,如果直接开就会产生错误,关于这点我也不知道为什么。。。以后知道了在做补充吧

6、谨记 DP是转态的转移

poj1837Balance

View Code
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <cstdlib>
using namespace std;

int dp[21][15001];

int main()
{
    int C, G;
    int a[25], g[25];
    while(cin >> C >> G) {
        for(int i = 1; i <= C; i++)
            cin >> a[i];
        for(int i = 1; i <= G; i++)
            cin >> g[i];
        memset(dp, 0, sizeof(dp));
        dp[0][7500] = 1;

        for(int i = 1; i <= G; i++) {
            for(int j = 0; j <= 15000; j++) {
                if(dp[i-1][j])
                    for(int k = 1; k <= C; k++)
                        dp[i][j+g[i]*a[k]] += dp[i-1][j];
            }
        }
        cout << dp[G][7500] << endl;
    }
    return 0;
}

7、背包问题

0/1背包,完全背包,多重背包模板如下

int dp[100005], vol[101], num[101];
int n, v;

void ZeroOnePack(int val, int vol) {
    for(int i = v; i >= vol; i--)
        dp[i] = max(dp[i], dp[i-vol]+val);
}

void CompletePack(int val, int vol) {
    for(int i = vol; i <= v; i++)
        dp[i] = max(dp[i], dp[i-vol]+val);
}

void MultiplePack(int val, int vol, int cnt) {
    if(val*vol >= v) {
        CompletePack(val, vol);
        return;
    }
    int k = 1;
    while(k < cnt) {
        ZeroOnePack(k*val, k*vol);
        cnt -= k;
        k = k*2;
    }
    ZeroOnePack(cnt*val, cnt*vol);
}

 

poj1276Cash Machine

View Code
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
using namespace std;

int dp[100005], vol[101], num[101];
int n, v;

void ZeroOnePack(int val, int vol) {
    for(int i = v; i >= vol; i--)
        dp[i] = max(dp[i], dp[i-vol]+val);
}

void CompletePack(int val, int vol) {
    for(int i = vol; i <= v; i++)
        dp[i] = max(dp[i], dp[i-vol]+val);
}

void MultiplePack(int val, int vol, int cnt) {
   /* if(val*vol >= v) {
        CompletePack(val, vol);
        return;
    }*/
    int k = 1;
    while(k < cnt) {
        ZeroOnePack(k*val, k*vol);
        cnt -= k;
        k = k*2;
    }
    ZeroOnePack(cnt*val, cnt*vol);
}

int main()
{
    while(scanf("%d%d", &v, &n) != EOF) {

        for(int i = 0; i <= v; i++)
            dp[i] = 0;

        for(int i = 0; i < n; i++) {
            scanf("%d%d", &num[i], &vol[i]);

            MultiplePack(vol[i], vol[i], num[i]);
        }
        printf("%d\n", dp[v]);
    }
    return 0;
}

 

 

posted on 2013-02-18 19:56  Lavare  阅读(214)  评论(0)    收藏  举报

导航