2016.5.23

来源:互联网 发布:国际学校知乎 编辑:程序博客网 时间:2024/05/21 15:37

1.数字三角形

动规第一道例题,很具有代表性。

动态规划解题思路:

①  将原问题分解成子问题

②  确定状态

③  确定初始状态的值,即递推自下而上的最底层初值

④  确定状态转移方程


2.最长上升子序列

两种动规方法 “我为人人”型 和 “人人为我”型 

自己感觉“人人为我”在大部分题目中比较容易想到

//人人为我for (int i = 2; i <= N; ++i)    for (int j = 1; j < i; ++j)    if (a[i] > a[j])        maxLen[i] = max(maxLen[i], maxLen[i] + 1);//我为人人for (int i = 1; i < N; ++i)    for (int j = i + 1; j <= N; ++j)        if (a[j] > a[i])            maxLen[j] = max(maxLen[j], maxlen[i] + 1);


3.最大上升子序列和

题目链接:  http://cxsjsx.openjudge.cn/2015finalpractice/30/

例题练习,稍微有改动, 就犯了些错误/(ㄒoㄒ)/~~

int main(){    int N;    int maxLen[1001];    int a[1001];    while (scanf("%d", &N) != EOF)    {        for (int i = 0; i < N; ++i)        {            scanf("%d", &a[i]);        }        maxLen[0] = a[0];        for (int i = 1; i < N; ++i)        {            maxLen[i] = a[i];//注意这里!一定要用a[i]初始化,否则可能会赋不上值                             //比如序列{102, 100, 101}            for (int j = 0; j < i; ++j)            {                if (a[i] > a[j])                    //与最长上升子序列类似的状态转移方程                    maxLen[i] = max(maxLen[i], maxLen[j] + a[i]);            }        }        int cmax = 0;        for (int i = 0; i < N; ++i)        {            if (cmax < maxLen[i])                cmax = maxLen[i];        }        printf("%d\n", cmax);    }    return 0;}

4.最长公共子序列

给出两个字符串,求出这样的一个最长的公共子序列的长度:子序列中的每个字符都能在两个原串中找到,而且每个字符的先后顺序和原串中的先后顺序一致。

状态:MaxLen[i][j]  :s1左边i个字符形成的子串和s2左边j个字符形成的子串的最长子序列长度。

//状态初始化for( i = 0;i <= length1; i ++ )    maxLen[i][0] = 0;for( j = 0;j <= length2; j ++ )    maxLen[0][j] = 0;for( i = 1;i <= length1;i ++ ) {    for( j = 1; j <= length2; j ++ )     {        //核心,状态转移方程,很有趣        if( sz1[i-1] == sz2[j-1] )            maxLen[i][j] = maxLen[i-1][j-1] + 1;        else            maxLen[i][j] = max(maxLen[i][j-1],maxLen[i-1][j]);    }}

5. UNIMODAL PALINDROMIC DECOMPOSITIONS

题目链接:http://cxsjsx.openjudge.cn/hw201614gw/A/

心得:很难想到...看了网上的代码才勉强理解,不过已知答案再回头分析也能够通过动规的思路来解释,看来还是要多积累经验

#define N 300int main(){    int i, j;    int n;    long long s[N][N];    memset(s, 0, sizeof(s));    //状态:s[i][j]i是待分解元素,表示i中元素大于等于j的序列个数,不太容易想到    for (j = 1; j < N; j++)        s[0][j] = 1;//i被拆成两个相同的数    for (i = 1; i < N; i++)        for (j = i / 2 + 1; j <= i; j++)            s[i][j] = 1;// j > i/2时只有一种情况就是i本身    for (i = 2; i < N; i++)        for (j = i / 2; j > 0; j--)            s[i][j] = s[i - 2 * j][j] + s[i][j + 1];//状态转移方程    while (scanf("%d", &n) && n)    {        printf("%d %lld\n", n, s[n][1]);//**oj的处理器似乎不能用I64**    }    return 0;}


0 0