zoukankan      html  css  js  c++  java
  • DP五十题

    目录

    板子

    范围

    集合

    转移

    终态

    初始化

    P1474 货币系统 Money Systems

    完全背包求方案数

    不限制每种货币取的个数,则需要使用完全背包,这里是统计方案数,根据加法原理(分步相加)得出转移方程:f[j]=f[j-a[i]].

    记得初始化f[0]=1;


    P1233 木棍加工

    思想:归约:按照第一个关键字从大到小排序后就只用考虑另一个关键字的降序问题;

    SOL:

    ​ 要求的是第二个关键字的最长下降子序列的最小个数,根据导弹拦截第二问用到的定理Dilworth定理:最少的下降序列个数就等于整个序列最长上升子序列的长度,求一遍LIS,因为n<=5e3,我就没用nlogn,(n^2)跑一边就好了

    const int N=5e3+10;
    struct qujian{
        int a,b;
        bool operator <(const qujian &rhs)const{
            if(a!=rhs.a)return a>rhs.a;
            return b>rhs.b;
        }
    }mg[N];
    
    int f[N],maxx,n;
    
    #undef int
    int main(){
    #define int long long
        #ifdef WIN32
        freopen("c.txt","r",stdin);
        #endif
        rd(n);
        rep(i,1,n){
            rd(mg[i].a),rd(mg[i].b);
        }
        sort(mg+1,mg+n+1);
        rep(i,1,n){
            f[i]=1;
            rep(j,1,i-1)
                if(mg[j].b<mg[i].b)
                    f[i]=max(f[i],f[j]+1);
            maxx=max(maxx,f[i]);
        }
        printf("%lld
    ",maxx);
        return 0;
    }
    

    好吧,还是悄咪咪复习一下O(nlogn)的做法

    	f[++len]=mg[1].b;
        rep(i,2,n){
            if(mg[i].b>f[len])f[++len]=mg[i].b;
            else{
                int p=lower_bound(f+1,f+len+1,mg[i].b)-f;//求按第二关键字的LIS
                f[p]=mg[i].b;
            }
        }
        printf("%lld
    ",len);
    

    P2904 USACO08MAR跨河River Crossing

    【前置技能】:语文足够好

    【独立思考+1A】

    设f[i]表示1~i只牛全部运输过去的最小花费

    预处理sum[i]:运i只牛的总花费

    转移方程:f[i]=min(f[i],f[i-j]+sum[j]+M)//加M只因为FJ还要回到对岸

    记得最后答案再减去一个M,因为最后一次到对岸的时候FJ已经不用再去接Bessie们了

    const int N=2510;
    int m[N],sum[N],f[N];
    int n,M,cnt;
    
    int main(){
        #ifdef WIN32
        freopen("c.txt","r",stdin);
        #endif
        rd(n),rd(M);
        sum[0]=M;
        rep(i,1,n){
            rd(m[i]);
            sum[i]=sum[i-1]+m[i];
        }
        mem(f,0x3f);
        f[0]=0;
        rep(i,1,n){
            rep(j,1,i){
                f[i]=min(f[i],f[i-j]+sum[j]+M);
            }
        }
        printf("%d",f[n]-M);
        return 0;
    }
    

    P1336 最佳课题选择

    范围:1e2的级别->(O(n^3))的算法

    集合:考虑物尽其用,给了m个课题就一个一个课题的去更新,记录前i个课题完成了j篇论文的最小时间。那么转移就可以根据m的阶段来划分,从m的上一个阶段递推。

    转移:这道题的转移方程挺容易想的:f[i][j]=min(f[i][j],f[i−1][j−k]+a[i]∗k^b[i])

    终态f[m][n]

    初始化:根据注意到i-1可能为0,那转移就从这里开始。

    const int N=210;
    int f[N][N];
    int n,m;
    int a[N],b[N];
    
    inline int ksm(int a,int k){
        int res=1;
        for(;k;k>>=1){
            if(k&1)res=res*a;
            a=a*a;
        }
        return res;
    }
    
    #undef int
    int main(){
    #define int long long
        #ifdef WIN32
        freopen("c.txt","r",stdin);
        #endif
        rd(n),rd(m);//n:论文数,m:课题数
        rep(i,1,m)rd(a[i]),rd(b[i]);
        rep(i,1,n)f[0][i]=INT_MAX;
        rep(i,1,m)
            rep(j,1,n){
                f[i][j]=INT_MAX;
                rep(k,0,j)
                    f[i][j]=min(f[i][j],f[i-1][j-k]+a[i]*ksm(k,b[i]));
            }
        printf("%lld
    ",f[m][n]);
        return 0; 
    }
    

    P2285 HNOI2004打鼹鼠

    很妙的LIS!!!

    朴素DP方法:f[i][j][k]机器人第k时刻在i,j的最大值,but!1e3的n和1e4的m直接炸掉!

    范围:1e4的级别->(O(n^2))的算法

    集合:发现地鼠的转移随时间递增(根据LIS的思想),能从上个地鼠转移到此时刻的地鼠的条件是在时间间隔内可以移动俩点的曼哈顿距离。

    转移

    if(abs(x[i]-x[j])+abs(y[i]-y[j])<=t[i]-t[j])
                    f[i]=max(f[i],f[j]+1);
    

    终态:记录f[i]的最大值

    初始化:f[i]=1

    但是此题不可以为了追求O(nlogn)而用 LIS 的优化,因为此题的序列没有传递性

    const int N=1e4+10;
    int x[N],y[N],t[N];
    int f[N];
    int n,m,maxx;
    
    #undef int
    int main(){
    #define int long long
        #ifdef WIN32
        freopen("c.txt","r",stdin);
        #endif
        rd(n),rd(m);
        rep(i,1,m){
            rd(t[i]),rd(x[i]),rd(y[i]);
        }
        rep(i,1,m){
            f[i]=1;
            rep(j,1,i-1){
                if(abs(x[i]-x[j])+abs(y[i]-y[j])<=t[i]-t[j])
                    f[i]=max(f[i],f[j]+1);
            }
            maxx=max(maxx,f[i]);
        }
        printf("%lld
    ",maxx);
        return 0; 
    }
    

    P1063 能量项链

    范围:1e2的级别->(O(n^3))的算法。区间DP的标准复杂度。

    集合f[l][r]表示目前已经合并l->r这段区间的最大值

    转移f[l][r]=max(f[l][r],f[l][k]+f[k][r]+a[l]*a[k]*a[r]);

    终态max{f[i][i+n]},这是个环形DP

    初始化f[i][i]=0但是我懒得打。

    int f[405][405];
    int n,a[205]; 
    
    int main(){
        #ifdef WIN32
        freopen("a.txt","r",stdin);
        #endif
        rd(n);
        rep(i,1,n)
            rd(a[i]),a[i+n]=a[i];
        rep(len,1,n)
            for(int l=1;l+len<=2*n;++l){
                int r=l+len;
                rep(k,l+1,r-1)
                    f[l][r]=max(f[l][r],f[l][k]+f[k][r]+a[l]*a[k]*a[r]);
            }
        int res=0;
        rep(i,1,n)
            res=max(res,f[i][n+i]);
        printf("%d",res);
        return 0;
    }
    

    P1077 摆花

    因为是求方案数,我们考虑当前这一种方案的上一个状态是什么。第i种花可以取k:0~a[ i ]个,那么前i-1种花的方案数有f[i-1][j-k]种,每一种都可以转移到当前状态,根据加法原理,直接相加。

    范围:1e2的级别->(O(n^3))的算法。区间DP的标准复杂度。

    集合f[i][j] 摆完前i种花共摆了j盆的方案。

    转移:见代码

    终态:RT,f[n][m]

    初始化f[0][0]=1

    const int N=1e3+10;
    const int mod=1000007;
    
    int f[N][N];//摆完前i种花共摆了j盆的方案。
    int a[N],n,m;
    
    int main(){
        rd(n),rd(m);
        rep(i,1,n)rd(a[i]);
        f[0][0]=1;
        rep(i,1,n)
            rep(j,0,m)
                rep(k,0,a[i])
                    if(j-k>=0)
                        f[i][j]=(f[i][j]+f[i-1][j-k])%mod;
        printf("%d",f[n][m]%mod);
        return 0;
    }
    

    P1417 烹调方案

    算法:01背包的带权变形,很显然嘛,如果不考虑t的影响,这题就是个裸的01背包,那么我们考虑t这个权值妖艳在哪里;

    现在考虑相邻的两个物品x,y。假设现在已经耗费p的时间,那么分别列出先做x,y的代价:

    a[x]-(t+c[x])* b[x]+a[y]-(t+c[x]+c[y])*b[y] (①)

    a[y]-(t+c[y])* b[y]+a[x]-(t+c[y]+c[x])*b[x] (②)

    对这两个式子化简,得到①>②的条件是c[x]* b[y]<c[y]*b[x].

    发现只要满足这个条件的物品对(x,y),x在y前的代价永远更优。

    因此可以根据这个条件进行排序,之后就是简单的01背包了。

    注意开long long,会爆int!!!见祖宗了呢

    const int N=55;
    
    struct data{
        int a,b,c;
        bool operator <(const data &rhs)const {
            return b*rhs.c>c*rhs.b;
        }
    }x[N];
    
    int T,n,ans;
    int f[100010];
    
    #undef int
    int main(){
    #define int long long
        rd(T),rd(n);
        rep(i,1,n){rd(x[i].a);}
        rep(i,1,n){rd(x[i].b);}
        rep(i,1,n){rd(x[i].c);}
        sort(x+1,x+n+1);
        rep(i,1,n)
            dwn(j,T,x[i].c){
                f[j]=max(f[j],f[j-x[i].c]+x[i].a-x[i].b*j);
                ans=max(ans,f[j]);
            }
        printf("%lld",ans);
        return 0;
    }
    

    P1412 经营与开发

    const int N=1e5+10;
    int op[N],x[N];
    double f[N];
    int n,k,c,w;
    
    int main(){
        rd(n),rd(k),rd(c),rd(w);
        rep(i,1,n){
            rd(op[i]),rd(x[i]);
        }
        dwn(i,n,1){
            if(op[i]==1)
                f[i]=max(f[i+1],f[i+1]*(1-0.01*k)+x[i]);
            else 
                f[i]=max(f[i+1],f[i+1]*(1+0.01*c)-x[i]);
        }
        printf("%.2lf",f[1]*w);
        return 0;
    }
    
  • 相关阅读:
    全国省市县三级数据库
    多源教学数据管理系统之团队课设博客
    1.判断字符串中的字符是否Unique
    [转载]linux防火墙基础和管理设置iptables规则
    (转)Sed使用详解
    2.判断回文(Anagrams)
    【转载】关于23 种设计模式的有趣见解
    macbook M1芯片在centos8下安装k8s笔记
    Winform 学习初级 从WebForm到WinForm
    如何建立数据模型
  • 原文地址:https://www.cnblogs.com/sjsjsj-minus-Si/p/11657214.html
Copyright © 2011-2022 走看看