2016.5.23

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 300

int 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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值