• 【经典】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不会考很难的吧。【逃

  • 相关阅读:
    Cable master--hdu1551(二分法)
    Pie--hdu1969(二分法)
    Ice_cream's world I--hdu2120
    How Many Tables--hdu1213(并查集)
    畅通工程--hdu1232(并查集)
    小希的迷宫--hdu1272(并查集)
    More is better--hdu1856(并查集)
    Windows Message Queue--hdu1509
    期末考试--nyoj-757
    网络开发之使用Web Service和使用WCF服务
  • 原文地址:https://www.cnblogs.com/zzyh/p/7806263.html
Copyright © 2020-2023  润新知