【经典】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\n",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\n",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\n",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.\n");
        else
        printf("The minimum amount of money in the piggy-bank is %d.\n",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\n",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\n",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\n",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\n",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\n",f[s[1]][s[2]][s[3]][s[4]]);
    return 0;
}
乌龟棋

 

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

 

posted @ 2017-11-08 21:20  ANhour  阅读(792)  评论(0编辑  收藏  举报