• dp(题型小结)


       好久没写总结了,问题积累了不少,把做过的题型分类总结一下了,下面这些题型也是我在hdu acm step里面碰到的类型题,重新梳理一下思路。

    题型一:

    http://acm.hdu.edu.cn/showproblem.php?pid=1003

    hdu1003思路前段时间已经叙述过了,在这里重点说一下这种题型的入手点,

     一看这种题型就是属于求最大子序列的和,切入点就是找到start和end,即起始位置以及结束位置。起初,我碰到这道题的时候,也是借鉴网上的一些办法,不过随着学习的不断深入,也逐渐有了点头绪,其实思路还是和网上的基本一致,但这只是借鉴和学习,并没有真正做到融会贯通,这还需要时间吧。希望在以后的学习中能加入自己的一些点子。具体思路看我的博客吧!

    题型二:

    http://acm.hdu.edu.cn/showproblem.php?pid=1159

    类似1003,但又有所不同,求解最大公共子序列的长度。也相当于是上一种的变形了,也就是传说中的LCS(刚学的时候感觉很神啊,呵呵),这种题也有模板,如下:

    View Code
    void LCS(char a[], char b[], int x, int y)
    {
    int i,j;
    for(i=0;i<=x;i++)
    c[i][
    0]=0;
    for(j=0;j<=y;j++)
    c[
    0][j]=0;

    for(i=1;i<=x;i++)
    {
    for(j=1;j<=y;j++)
    {
    if(a[i-1]==b[j-1]) {c[i][j]=c[i-1][j-1]+1;}
    else { c[i][j]=Max( c[i][j-1], c[i-1][j]);}
    }
    }
    }

    这是hdu课件里边的方法,方法不错,也就拿来学习了,这种思维对于惯性思维来说还是有挑战性的,当时我为了弄明白这个题,整整花了一个下午的时间。到最后终于知道是怎么回事了。

       其中,c[i][j]表示a中的第i个字符和b中的第j个字符相比较,结果为两串相比较前的a中前i个字符和b中前j个公共字符的长度,c[i][j]=c[i-1][j-1]+1,表示在a[i-1]和b[j-1]相等的情况下,使其相等字符的个数加1,即c[i-1][j-1]+1,否则,c[i][j]=Max( c[i][j-1], c[i-1][j]),解释为在a中的第i个和b中第j个不相等的时候,那么就需要从前面a中的第i个和b中的第j-1个的值以及a中的第i-1个和b中的第j个寻找一个最大的赋给c[i][j],这样方便下一次比较。

       这里面就有很强的动态性,即最大子序列长度的传递性,利用二维数组,将本来间断的关系线性化。

     for(i=0;i<=x;i++)
            c[i][
    0]=0;
       
    for(j=0;j<=y;j++)
            c[
    0][j]=0;
    这是在没有比较之前,结果都为0。

    题型三:

    http://acm.hdu.edu.cn/showproblem.php?pid=1087

    这个题,刚开始我用dfs做的,结果超时,剪枝也不好使。后来估计这可能是dp, 根据dfs的思路一想,后来也看了网上的报告,的确是!

    这是我刚开始用dfs做的,其实dp和dfs的思路一个样,只是从时间上比dfs快了不少。

    dfs
    #include"iostream"
    using namespace std;
    int a[1010];
    int n,sum;
    int p=0;
    void dfs(int x,int y)
    {
    while(y<=x&&x<n) y++;

    if(a[x]<a[y]&&y<n&&x<n)
    {
    sum
    +=a[y];
    x
    =y;
    if(x<n-1&&y<n-1) dfs(x,y);
    }
    else if(y<n-1){ y++; if(y<n-1) dfs(x,y);}
    }
    int main()
    {
    int i,j;
    while(cin>>n,n)
    {
    for(i=0;i<n;i++) cin>>a[i];
    int Max=-1;
    sum
    =0;
    for(i=0;i<n;i++)
    {
    sum
    =a[i];
    if(Max<sum) Max=sum;
    for(j=i+1; j<n; j++)
    {
    p
    =0;
    if(a[i]<a[j])
    {
    sum
    +=a[j];
    dfs(j,p);
    }
    if(sum>Max) Max=sum;
    sum
    =a[i];
    }
    }
    cout
    <<Max<<endl;
    }
    return 0;
    }

    后来,看了一下网上的解题报告,很快思路就有了。

    状态转移方程  b[i]=max(b[i], b[j]+a[i]),关键点,比dfs省去了许多不必要的计算步骤,核心代码:

    View Code
    for(i=1;i<n;i++)
    {
    b[i]
    =a[i];
    for(j=0;j<i;j++)
    if(a[j]<a[i]&&b[i]<b[j]+a[i])
    b[i]
    =b[j]+a[i];
    if(b[i]>Max) Max=b[i];
    }


    这个也容易理解,a[j]<a[i]是判断棋子是否是按照递增的顺序走的,至于b[i]<b[j]+a[i],是判断前i段的和和前j段的和加上第i个数是比较,找一个最大的。

    最后和Max比较即可求出最大值。

    题型四:

    http://acm.hdu.edu.cn/showproblem.php?pid=1160

    早上好!继续了!

       这道题思路简单,刚开始用搜索做的结果一直w,不知道为什么,当时看数据量也不是很大,1000也不大啊,时间复杂度最带也就是O(n^2),其实真正运行达不到这个时间,估摸着又是dp了,后来借鉴网上的方法,改为dp, 也过了。核心代码:

    View Code
    for(i=1;i<k;i++)
    {
    a[i]
    =1; b[i]=-1;
    for(j=i-1;j>=1;j--)
    {
    if(s[i].w>s[j].w && s[i].v<s[j].v && a[j]+1>a[i])
    {
    a[i]
    =a[j]+1;
    b[i]
    =j;
    }
    }

    if(a[i]>Max)
    {
    Max
    =a[i];
    flag
    =i;
    }
    }

    状态转移方程:

    a[i]=a[j]+1;
          b[i]=j;  其实,b[i]用于标记路径。同前面几个一样,a[i]记录的是最长递增子序列。条件限制 s[i].w>s[j].w && s[i].v<s[j].v && a[j]+1>a[i],表示为在质量严格递增,速度严格递减的情况下,比较a[i]和a[j]+1。

    题型五:

    http://acm.hdu.edu.cn/showproblem.php?pid=2571

       原来这是个系列题,挺有意思,有兴趣的可以做一做,网址:http://acm.hdu.edu.cn/search.php?field=problem&key=ACM。前段时间在poj上做过一个类型题,http://poj.org/problem?id=2704 不过这个题里面已经给出状态转移方程,dp[i][j],dp[i+1][y],dp[i][k*y](k>1),这样就使问题简单了不少。核心代码如下,

    View Code
      
    for(i=1;i<=n;i++)
    {
    for(j=1;j<=m;j++)
    {
    if(j!=1) dp[i][j]=Max(dp[i][j], dp[i][j-1]+a[i][j]);
    if(i!=1) dp[i][j]=Max(dp[i][j] , dp[i-1][j]+a[i][j]);

    for(int p=2;p<=m; p++)
    {
    if(j*p>m) break;
    dp[i][j
    *p]=Max(dp[i][j]+a[i][j*p] , dp[i][j*p] );
    }
    }
    }

    题型6:

    http://acm.hdu.edu.cn/showproblem.php?pid=1176

     开始没什么思路,这道也是dp问题,但找不到突破点,后来上网一查,很出乎意料,竟尽然是数塔模型。只好借鉴了,到现在没其他思路。慢慢想吧。

    代码如下,

    View Code
    for(i=1;i<=n;i++)
    {
    cin
    >>a>>b;
    dp[b][a]
    ++;
    if(Max<b) Max=b;
    }

    for(i=Max ; i>=1; i--)
    {
    for(j=0;j<=10; j++)
    {
    if(j==0)
    dp[i
    -1][j]+=MAX(dp[i][j], dp[i][j+1]);
    else if(j==10)
    dp[i
    -1][j]+=MAX(dp[i][j-1],dp[i][j]);
    else
    dp[i
    -1][j]+=MAX(MAX(dp[i][j-1], dp[i][j]),dp[i][j+1]);
    }
    }
    cout
    <<dp[0][5]<<endl;

    具体思路还在思考过程中。。。。。。

         

     

  • 相关阅读:
    7-感觉身体被掏空,但还是要学Pandas(下)
    6-感觉身体被掏空,但还是要学Pandas(上)
    5-Numpy似双丝网,中有千千结(下)
    4-Numpy似双丝网,中有千千结(上)
    3-上帝说要有光,于是就有了Python(下)
    2-上帝说要有光,于是就有了Python(上)
    1-在IPython Notebook中愉快地使用python编程
    第11组 Alpha冲刺(2/6)
    第11组 Alpha冲刺(1/6)
    2019 SDN上机第2次作业
  • 原文地址:https://www.cnblogs.com/FCWORLD/p/2036948.html
Copyright © 2020-2023  润新知