zoukankan      html  css  js  c++  java
  • 经典dp模型的变形(未完待续。。)

    这几天做了几道dp题,发现有几道是很经典的dp模型的变形,总结一下:

    数字三角形

    这算是dp的最最最入门的题了吧,但是这题变形的话,还是需要好好想想才能看出来的。
    题目:hdu 1176 免费馅饼
    题意:

    一定时间,天上会从某个位置Xi掉下一块馅饼,1< =xi< =10,这个人位于xi,只能接到xi-1,xi,xi+1,三处之一,问这人可以接到的最多馅饼?

    分析:

    这题想想还是挺有意思的QAQ,因为是按照时间落馅饼,所以dp的方向是显然的,就是按照时间,第二维当然就是位置了!所以用dp[i][j]表示在i时刻这个人在j位置可以得到的最大馅饼数,num[i][j]表示i时刻j位置落下的馅饼数,不难写出dp方程:
    dp[i][x]=max(dp[i-1][x-1],dp[i-1][x],dp[i-1][x+1])+num[i][x]
    想明白后,0时刻在5这个位置,然后顺着时间转移,转移到最后一块馅饼落下的时刻,那么这题不就做出来了吗?当然可以!注意下边界即可。
    仔细想想这题,这不就是数字三角形吗?所以逆推很容易就可以搞定了!

    const int N=1e5+2;
    int n,x,T,t,f[N][11];
    int main()
    {
        while(~scanf("%d",&n)&&n){
            T=0;
            memset(f,0,sizeof(f));
            for(int i=0;i<n;i++){
                scanf("%d%d",&x,&t);
                f[t][x]++;
                if(T<t)T=t;
            }
            for(int i=T-1;i>=0;i--){
                for(int j=1;j<=9;j++)
                    f[i][j]+=max(f[i+1][j+1],max(f[i+1][j],f[i+1][j-1]));
                f[i][0]+=max(f[i+1][0],f[i+1][1]);
                f[i][10]+=max(f[i+1][10],f[i+1][9]);
            }
            cout<<f[0][5]<<endl;
        }
        return 0;
    }

    背包问题

    背包问题无疑是变形最多的一类dp题,要想掌握好这类题目,关键还是要深刻理解01背包和完全背包!当然还有更多变形,像分组背包,有依赖的背包,泛化背包等,都是些不好掌握的东东,当然做题时如果能看出这是背包的题目,就离解决问题更近了一大
    步!
    (此处应有各种背包的分类,等多做几道题后再补QAQ)

    完全背包

    题目:hdu 1114 Piggy-Bank
    题意:

    存钱罐里有一些硬币,总共重量是F,空罐重量是E,给出n种钱币,每种钱币的有两个参数,v价值,w重量。问存钱罐中最少的价值是多少?

    分析:

    赤裸裸的完全背包的题目,注意初始化。

    const int INF=0x3f3f3f3f;
    const int N=1e4+9;
    int n;
    int E,F;
    int f[N],p[N],w[N];
    int main()
    {
        int T; scanf("%d",&T);
        while(T--){
            scanf("%d%d",&E,&F);
            F-=E;
            scanf("%d",&n);
            for(int i=1;i<=n;i++){
                scanf("%d%d",&p[i],&w[i]);
            }
            for(int i=1;i<=F;i++)f[i]=INF;
            f[0]=0;
            for(int i=1;i<=n;i++){
                for(int v=w[i];v<=F;v++)
                    f[v]=min(f[v],f[v-w[i]]+p[i]);
            }
            if(f[F] == INF)
                printf("This is impossible.
    ");
            else
                printf("The minimum amount of money in the piggy-bank is %d.
    ",f[F]);
        }
        return 0;
    }

    最长上升子序列 LIS

    最长上升子序列变形是比较多的,可以先看我以前写的这篇:http://blog.csdn.net/hjt_fathomless/article/details/52176146
    题目的话,有很多,比如矩形嵌套(按一边排序后,就可以LIS了),叠木块等!
    题目:http://blog.csdn.net/hjt_fathomless/article/details/52176513

    最长公共子序列 LCS

    我记得以前在bestcoder上做过一道很好的变形题,不过忘了QAQ。等看到了再补吧!
    不过重要的还是记住状态转移方程,知道怎么得到的!

    简单的dp题

    简单的dp题是什么东西?就是决策是显然的,一般递推就可以解决,这种题决策都不会太复杂(反正复杂的我也不会做QAQ),而且方向是明显的,所以是简单的。
    比如走楼梯那种题,只有两个决策,一步or两步,方向是从0—n(楼底到楼上)。再比如上边所述的数字三角形,决策和方向都是很容易看出来的(所以才是入门题啊)。碰见这种题,那就偷着乐吧!
    题目:hdu 1260 Tricks
    题意:

    售票员有两种选择,一次一票or两票,问花时最少?

    分析:

    这题是不是很简单,决策是显然的,一票or两票,方向从第一个人到最后一个人楼,这不是跟走楼梯那题一样吗?所以是简单dp!

    const int N=1e5+2;
    int a[N],b[N],f[N],t[5];
    char c[5];
    int main()
    {
        int n;
        int T;scanf("%d",&T);
        while(T--){
            scanf("%d",&n);
            for(int i=1;i<=n;i++)scanf("%d",&a[i]);
            for(int i=2;i<=n;i++)scanf("%d",&b[i]);
            f[1]=a[1];
            for(int i=2;i<=n;i++)
                f[i]=min(f[i-1]+a[i],f[i-2]+b[i]);
            t[1]=f[n]/3600; f[n]%=3600;
            t[2]=f[n]/60;   f[n]%=60;
            t[3]=f[n];
            t[1]+=8;
            c[1]='a'; c[2]='m';
            if(t[1]>12){
                t[1]-=12;
                c[1]='p';
            }
            printf("%02d:%02d:%02d %c%c
    ",t[1],t[2],t[3],c[1],c[2]);
    
        }
        return 0;
    }
  • 相关阅读:
    VUE 多页面配置(二)
    VUE 多页面配置(一)
    VUE (vue-cli)脚手架项目说明
    CSS 三角形与圆形
    协同过滤算法之组合加权评分
    用户投票算法
    Android开发学习总结(一)——搭建最新版本的Android开发环境
    关于统计变换(CT/MCT/RMCT)算法的学习和实现
    SIFT 特征提取算法总结
    Android Listener侦听的N种写法
  • 原文地址:https://www.cnblogs.com/01world/p/5824082.html
Copyright © 2011-2022 走看看