zoukankan      html  css  js  c++  java
  • 【经典】Noip动态规划

    一、线性动态规划

    最长严格上升子序列

    #include<iostream>
    #include<cstdio>
    using namespace std;
    int n,ans;
    int a[5004],dp[5004];
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<i;j++)
            {
                if(a[j]<a[i])
                dp[i]=max(dp[i],dp[j]+1);
                ans=max(ans,dp[i]);
            }
        }
        printf("%d
    ",ans+1);
        return 0;
    }
    最长严格上升子序列
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int maxn=0x3f3f3f3f;
    int n,a[1000009],dp[1000009];
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
        memset(dp,0x3f,sizeof(dp));
        for(int i=1;i<=n;i++)
        {
            int p=upper_bound(dp+1,dp+n+1,a[i])-dp;
            if(a[i]!=dp[p-1])//严格上升序列 
            dp[p]=a[i];
        }
        for(int i=1;i<=n+1;i++)
        {
            if(dp[i]==maxn)
            {
                printf("%d
    ",i-1);
                return 0;
            }
        }
        return 0;
    }
    nlogn

    变形:打鼹鼠

    #include<iostream>
    #include<cstdlib>
    #include<cstdio> 
    using namespace std;
    int maxt,n,m,ans,x[10001],y[10001],t[10001],f[10001];
    int main()
    {
        int i,j;
        scanf("%d%d",&n,&m);
        for (i=1;i<=m;++i)
            scanf("%d%d%d",&t[i],&x[i],&y[i]);
        for (i=1;i<=m;++i)
        {
            f[i]=1;//f表示到第i只鼹鼠出现时最多可以打到多少只 
            for (j=i-1;j>=1;--j)
                if (t[i]-t[j]>=abs(x[i]-x[j])+abs(y[i]-y[j]))
                //如果时间足够,能从j点移动到当前点 
                    f[i]=max(f[i],f[j]+1);
            ans=max(ans,f[i]);
        }
        printf("%d",ans);
    }
    Luogu打鼹鼠

    二、背包

    1)01背包

    每个物品只有一个且只有选与不选两种可能

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    int f[1002],w[1001],v[1001];
    int n,m,t;
    int main()
    {
        scanf("%d",&t);
        while(t--)
        {
            memset(f,0,sizeof(f));
            scanf("%d%d",&n,&m);
            for(int i=1;i<=n;i++)
            scanf("%d",&v[i]);
            for(int i=1;i<=n;i++)
            scanf("%d",&w[i]);
            for(int i=1;i<=n;i++)
            for(int j=m;j>=w[i];j--)
            f[j]=max(f[j],f[j-w[i]]+v[i]);
            printf("%d
    ",f[m]);
        } 
        return 0;
    }
    01背包

    2)完全背包

    每件物品数量无限

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    int w1,w2,wi,t,k,f[10002],v[510],w[510];
    int main()
    {
        scanf("%d",&t);
        while(t--)
        {
            memset(f,0x3f,sizeof(f));
            f[0]=0; //**
            scanf("%d%d",&w1,&w2);
            wi=w2-w1;
            scanf("%d",&k);
            for(int i=1;i<=k;i++)
            scanf("%d%d",&v[i],&w[i]);
            for(int i=1;i<=k;i++)
            for(int j=w[i];j<=wi;j++)
            f[j]=min(f[j],f[j-w[i]]+v[i]);
            if(f[wi]==0x3f3f3f3f)
            printf("This is impossible.
    ");
            else
            printf("The minimum amount of money in the piggy-bank is %d.
    ",f[wi]);
        }
        return 0;
    }
    完全背包

    3)多重背包

    每个物品数量一定

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    int t,mon,k,w[102],pri[102],f[102],cnt[102];
    int main()
    {
        scanf("%d",&t);
        while(t--)
        {
            memset(f,0,sizeof(f));
            scanf("%d%d",&mon,&k);
            for(int i=1;i<=k;i++)
            scanf("%d%d%d",&pri[i],&w[i],&cnt[i]);
            for(int i=1;i<=k;i++)
            {
                for(int j=mon;j>=pri[i];j--)
                {
                    for(int h=0;h<=cnt[i];h++)
                    {
                        if(j-h*pri[i]<0)break;
                        f[j]=max(f[j],f[j-h*pri[i]]+h*w[i]);
                    }
                }
            }
            printf("%d
    ",f[mon]);
        }
        return 0;
    }
    多重背包

    4)混合背包

    -1为无限个

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    using namespace std;
    int w[100000],v[100000],c[10000],dp[20000000];
    int main()
    {
        int vv,n;
        scanf("%d%d",&n,&vv);
        for(int i=1;i<=n;i++)
        scanf("%d%d%d",&w[i],&v[i],&c[i]);
        for(int i=1;i<=n;i++)
        {
            if(c[i]==-1)
            {
                for(int j=w[i];j<=vv;j++)
                {
                    dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
                }
            }
            else
            {
                int x=c[i];
                for(int j=1;j<=x;j<<=1)
                {
                    for(int k=vv;k>=w[i]*j;k--)
                    {
                        dp[k]=max(dp[k],dp[k-w[i]*j]+v[i]*j);
                    }    
                    x-=j;
                }
                if(x!=0)
                {
                    for(int j=vv;j>=x*w[i];j--)
                    {
                        dp[j]=max(dp[j],dp[j-x*w[i]]+v[i]*x);
                    }
                }
            }
        }
        printf("%d",dp[vv]);
        return 0;
    }
    混合背包

    5)二维费用背包

    #include<bits/stdc++.h>
    using namespace std;
    int f[1010][1010];
    int main(){
        int n,m,x;
        cin>>n>>m>>x;
        for(int i=1;i<=n;i++){
            int a,b,c;
            cin>>a>>b>>c;
            for(int j=m;j>=b;j--)                                     //以下3行是算法的核心
                for(int k=x;k>=c;k--)
                    f[j][k]=max(f[j][k],f[j-b][k-c]+a);
        }
        cout<<f[m][x];
        return 0;
    }
    二维费用

    6)有依赖性背包问题

    #include<iostream>
    #include<cstdio>
    using namespace std;
    struct e
    {
        int v,p,q,w,f[66];
    }g[66];
    int n,m,f[35000];
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&g[i].v,&g[i].p,&g[i].q);
            g[i].w=g[i].v*g[i].p;
            if(g[i].q!=0)
            g[g[i].q].f[++g[g[i].q].f[0]]=i;
        }
        for(int i=1;i<=m;i++)
        {
            if(g[i].q==0)
            {
                int f1=g[i].f[1],f2=g[i].f[2];
                for(int j=n;j>=g[i].v;j--)
                {
                    if(f1&&j-g[f1].v-g[i].v>=0)
                    f[j]=max(f[j],f[j-g[i].v-g[f1].v]+g[i].w+g[f1].w);
                    if(f2&&j-g[f2].v-g[i].v>=0)
                    f[j]=max(f[j],f[j-g[i].v-g[f2].v]+g[i].w+g[f2].w);
                    if(f1&&f2&&j-g[i].v-g[f1].v-g[f2].v>=0)
                    f[j]=max(f[j],f[j-g[i].v-g[f1].v-g[f2].v]+g[i].w+g[f1].w+g[f2].w);
                    f[j]=max(f[j],f[j-g[i].v]+g[i].w);
                    
                }
            }
        }
        printf("%d
    ",f[n]);
        return 0;
    }
    依赖性背包

    7)01背包求方案数

    #include<iostream>
    #include<cstdio>
    using namespace std;
    int f[10000],n,m,a[110];
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        f[0]=1;
        for(int i=1;i<=n;i++)
            for(int j=m;j>=a[i];j--)
                f[j]+=f[j-a[i]];
        printf("%d",f[m]);
    }
    01背包求方案数

    三、区间型dp

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    int w[101],f[101][101],sum[101];
    int n;
    int main() {
        scanf("%d",&n);
        for(int i=1; i<=n; i++) {
            scanf("%d",&w[i]);
            sum[i]=sum[i-1]+w[i];
        }
        for(int i=2; i<=n; i++)
            for(int j=i-1; j>=1; j--) {
                f[j][i]=0x3f3f3f3f;
                for(int k=j; k<i; k++)
                    f[j][i]=min(f[j][i],f[j][k]+f[k+1][i]+sum[i]-sum[j-1]);
            }
    
        printf("%d
    ",f[1][n]);
        return 0;
    }
    合并果子

    四、概率dp

    #include<iostream>
    #include<cstdio>
    using namespace std;
    int n;
    double dp[1280][1280];
    int main(){
        scanf("%d",&n);n/=2;
        for(int i=2;i<=n;i++)dp[i][0]=dp[0][i]=1.0;
        for(int i=1;i<=n;i++)
         for(int j=1;j<=n;j++) 
          dp[i][j]=(dp[i-1][j]+dp[i][j-1])/2.0;
        printf("%.4lf
    ",dp[n][n]);
        return 0;
    }
    搞笑世界杯

    五、多维dp

    #include<iostream>
    #include<cstdio>
    using namespace std;
    int n,m,x,maxx,s[5],qp[355],f[40][40][40][40];
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        scanf("%d",&qp[i]);
        for(int i=1;i<=m;i++)
        {
            scanf("%d",&x);
            if(x==1)s[1]++;
            if(x==2)s[2]++;
            if(x==3)s[3]++;
            if(x==4)s[4]++;
        }
        f[0][0][0][0]=qp[1];
        f[1][0][0][0]=qp[2];
        f[0][1][0][0]=qp[3];
        f[0][0][1][0]=qp[4];
        f[0][0][0][1]=qp[5];
        for(int i=0;i<=s[1];i++)
        for(int j=0;j<=s[2];j++)
        for(int l=0;l<=s[3];l++)
        for(int k=0;k<=s[4];k++)
        {
            maxx=0;
            if(i)maxx=max(maxx,f[i-1][j][l][k]);
            if(j)maxx=max(maxx,f[i][j-1][l][k]);
            if(l)maxx=max(maxx,f[i][j][l-1][k]);
            if(k)maxx=max(maxx,f[i][j][l][k-1]);
            f[i][j][l][k]=maxx+qp[i+j*2+l*3+k*4+1];
         } 
         printf("%d
    ",f[s[1]][s[2]][s[3]][s[4]]);
        return 0;
    }
    乌龟棋

    整理的不全,noip不会考很难的吧。【逃

  • 相关阅读:
    Python 存储引擎 数据类型 主键
    Python 数据库
    Python 线程池进程池 异步回调 协程 IO模型
    Python GIL锁 死锁 递归锁 event事件 信号量
    Python 进程间通信 线程
    Python 计算机发展史 多道技术 进程 守护进程 孤儿和僵尸进程 互斥锁
    Python 异常及处理 文件上传事例 UDP socketserver模块
    Python socket 粘包问题 报头
    Django基础,Day7
    Django基础,Day6
  • 原文地址:https://www.cnblogs.com/zzyh/p/7806263.html
Copyright © 2011-2022 走看看