• poj 几道简单的dp题


    题目:poj 1836

    题意:
    求使数列程先递增后递减的形式需要去掉的数字个数。当然也可以直接递减或者只递减不递增。
    分析:
    用最长递增子序列的方法求,然后枚举两个起点的位置即可。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int INF=1e8;
    const int N=1000+9;
    void LIS(int n,int d[],double g[],double A[]) //Nlog(N)
    {
        for(int i=1;i<=n;i++)g[i]=INF;
        for(int i=0;i<n;i++){
            int k=lower_bound(g+1,g+1+n,A[i])-g;
            d[i]=k;
            g[k]=A[i];
        }
    }
    int d1[N],d2[N];
    double a[N],b[N],g[N];
    int n;
    int main()
    {
       // freopen("f.txt","r",stdin);
        scanf("%d",&n);
        for(int i=0;i<n;i++)scanf("%lf",&a[i]),b[n-i-1]=a[i]; //b翻转过来
        LIS(n,d1,g,a);
        LIS(n,d2,g,b);
        int maxn=0;
        for(int i=0;i<n;i++)
            for(int j=0;j<n-i-1;j++)maxn=max(maxn,d1[i]+d2[j]);
        printf("%d
    ",n-maxn);
        return 0;
    }
    

    题目:poj 1260

    题意:
    给出几类珍珠,以及它们的单价,要求用最少的钱就可以买到相同数量的,相同(或更高)质量的珍珠。
    【规定买任一类的珍珠n个(价格为p),都要支付(n+10)*p的钱,即额外支付10*p】
    分析:
    f[i]表示到第i个品类最少花费。
    那么f[i]=min{ f[j]+(num[j+1]+num[j+2]+….+num[i])*p[i] }(j

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int INF=1e8;
    const int N=100+9;
    /*
    f[i]表示到第i个品类最少花费。
    那么f[i]=min{ f[j]+(num[j+1]+num[j+2]+....+num[i])*p[i] }
    */
    int n,ans;
    int num[N],p[N],f[N];
    int main()
    {
      // freopen("f.txt","r",stdin);
        int T;scanf("%d",&T);
        while(T--){
            ans=INF;
            scanf("%d",&n);
            for(int i=1;i<=n;i++){
                scanf("%d%d",&num[i],&p[i]);
            }
            f[0]=0;
            for(int i=1;i<=n;i++){
                int minn=INF,cnt=num[i];
                for(int j=i-1;j>=0;j--){
                    minn=min(minn,f[j]+(cnt+10)*p[i]);
                    cnt+=num[j];
                }
                f[i]=minn;
            }
    
            printf("%d
    ",f[n]);
        }
        return 0;
    }
    

    poj 1080

    题意:
    LCS变形题,根据LCS的思想去推dp方程即可。

    #include<cstdio>
    #include<iostream>
    using namespace std;
    const int mod=998244353;
    const int N=111;
    int w[300][300],f[N][N];
    char s1[111],s2[111];
    int main()
    {
        //freopen("f.txt","r",stdin);
        w['A']['A']=w['C']['C']=w['G']['G']=w['T']['T']=5;
        w['A']['C']=w['C']['A']=w['A']['T']=w['T']['A']=w['T']['-']=w['-']['T']=-1;
        w['A']['G']=w['G']['A']=w['C']['T']=w['T']['C']=w['G']['-']=w['-']['G']=-2;
        w['G']['T']=w['T']['G']=-2;
        w['A']['-']=w['-']['A']=w['C']['G']=w['G']['C']=-3;
        w['C']['-']=w['-']['C']=-4;
        int T;scanf("%d",&T);
        while(T--){
            int n1;scanf("%d%s",&n1,s1+1);
            int n2;scanf("%d%s",&n2,s2+1);
            int ans=0;
            f[0][0]=0;
            for(int i=1;i<=n1;i++)f[i][0]=f[i-1][0]+w[s1[i]]['-'];
            for(int j=1;j<=n2;j++)f[0][j]=f[0][j-1]+w['-'][s2[j]];
            for(int i=1;i<=n1;i++){
                for(int j=1;j<=n2;j++){
                    f[i][j]=f[i-1][j-1]+w[s1[i]][s2[j]];
                    f[i][j]=max(f[i][j],f[i-1][j]+w[s1[i]]['-']);
                    f[i][j]=max(f[i][j],f[i][j-1]+w['-'][s2[j]]);
                }
            }
            printf("%d
    ",f[n1][n2]);
        }
        return 0;
    }
    

    poj 1159

    题意:
    给一个字符串,问最少插入几个字符可以构成回文串?
    分析:
    求一下正串和逆串的最长公共子序列,就是最大可以匹配的,那么最少插入的就是n-LCS。
    这题n<=5000,用int f[N][N]会超内存,可以改成short,也可以用滚动数组。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N=5001;
    char a[N],b[N];
    short f[2][N];
    int n;
    int main()
    {
        //freopen("f.txt","r",stdin);
        scanf("%d%s",&n,a+1);
        for(int i=1;i<=n;i++)b[n-i+1]=a[i];
        f[0][0]=0;
        int k=0;
        for(int i=1;i<=n;i++){
            k=1^k;
            for(int j=1;j<=n;j++){
                if(a[i]==b[j])f[k][j]=f[k^1][j-1]+1;
                else f[k][j]=max(f[k^1][j],f[k][j-1]);
            }
        }
        printf("%d
    ",n-f[k][n]);
        return 0;
    }
    

    poj 2479

    题意:
    给出一个整数序列,求最大的两段连续序列和。
    分析:
    类似于poj1836那题,求一下从左端开始的最大序列和f[i],从右端开始的最大序列和d[i]。然后枚举中点即可。
    f[i]表示从左端到i点的一段最大的连续序列和
    d[i]表示从右端到i点的一段最大的连续序列和

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    using namespace std;
    const int INF=5e8;
    const int N=50001;
    int f[N],d[N],a[N];
    int n;
    int main()
    {
        //freopen("f.txt","r",stdin);
        int T;scanf("%d",&T);
        while(T--){
            memset(f,0,sizeof(f));
            memset(d,0,sizeof(d));
            scanf("%d",&n);
            for(int i=1;i<=n;i++)scanf("%d",&a[i]);
            int sum=a[1],maxn=a[1];
            f[1]=a[1];
            for(int i=2;i<=n;i++){
                if(sum<0)sum=0;
                sum+=a[i],maxn=max(sum,maxn);
                f[i]=maxn;
            }
            sum=maxn=d[n]=a[n];
            for(int i=n-1;i>=1;i--){
                if(sum<0)sum=0;
                sum+=a[i],maxn=max(sum,maxn);
                d[i]=maxn;
            }
            int ans=-INF;
            for(int i=1;i<n;i++){
    
                ans=max(ans,f[i]+d[i+1]);
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    
    /*
    3
    10
    1 -1 2 2 3 -3 4 -4 5 -5
    2
    1 -1
    3
    1 -1 2
    */
  • 相关阅读:
    感知器算法--python实现
    PHP appserv + ZendStudio12.5.1 + 注册码
    第九周-每周例行报告
    第八周-每周例行报告
    感谢THUNDER
    第七周-每周例行报告
    第六周-每周例行报告
    第五周-每周例行报告
    第四周-四则运算试题生成
    第四周-单元测试
  • 原文地址:https://www.cnblogs.com/01world/p/5762836.html
Copyright © 2020-2023  润新知