zoukankan      html  css  js  c++  java
  • 15.3.14 DP练习2

    拦截导弹

    题目

    某国为了防御敌国的导弹突击,发展出一种导弹拦截系统。

    可是这样的导弹拦截系统有一个缺陷:尽管它的第一发炮弹可以到达随意的高度。可是以后每一发炮弹都不能高于前一发的高度。

    某天,雷达捕捉到敌国的导弹来袭。因为该系统还在试用阶段。所以仅仅有一套系统,因此有可能不能拦截全部的导弹。


    输入数据:
    第一行为一个整数N。表示飞来的导弹个数。N<=100000
    第二行为N个整数,依次表示导弹飞来的高度。高度数据为不大于30000的正整数。


    输出数据:
    第一行。输出计算这套系统最多能拦截多少导弹
    第二行。输出要拦截全部导弹最少要配备多少套这样的导弹拦截系统。


    输入文件:missile.in
    8
    389 207 155 300 299 170 158 65


    输出文件:missile.out
    6 2


    分析

    求个最长不上升子序列长度。一个上升子序列长度。
    因为数据范围奇葩,所以用单调栈乱搞到nlog(n)

    代码

    #include <cstdio>
    #include <string>
    #include <algorithm>
    #define R1(i,n) for(register int i=1;i<=n;++i)
    using namespace std;
    template <class T> inline void read(T&x){
        bool f=false;char ch;
        for(ch=getchar();ch<=32;ch=getchar());
        if (ch=='-')f=true,ch=getchar();
        for(x=0;ch>32;ch=getchar()) x=x*10+ch-'0';
        if(f)x=-x;
    }
    template <class T> inline void write(T x){
        if(x<0)putchar('-'),x=-x;
        if(x<10)putchar(x + '0');
        else write(x / 10),putchar(x%10+'0');
    }
    template <class T> inline void writeln(T x){
        write(x);puts("");
    }
    void setIO(string t){
    string a=t+".in",b=t+".out";
    freopen(a.c_str(),"r",stdin);
    freopen(b.c_str(),"w",stdout);
    }
    int n,cnt;
    int s1[100010],s2[100010],temp;
    int main(){
        setIO("missile");
        read(n);
        int top1=0,top2=0;
        s1[0]=-1,s2[0]=0x3f3f3f3f;
        R1(i,n){
            read(temp);
            if(temp>s1[top1])s1[++top1]=temp;
            else{
                int _l=1,_r=top1;
                int mid;
                while(_l<=_r){
                    mid=(_l+_r)/2;
                    if(temp>s1[mid])_l=mid+1;
                    else _r=mid-1;
                }
                s1[_l]=temp;
            }
            if(temp<=s2[top2])s2[++top2]=temp;
            else{
                int _l=1,_r =top2;
                int mid;
                while(_l<=_r){
                    mid=(_l+_r)/2;
                    if (temp<=s2[mid])_l=mid+1;
                    else _r=mid-1;
                }
                s2[_l]=temp;
            }
        }
    writeln(top2),writeln(top1);
    return 0;
    }

    整数划分

    题目

    怎样把一个正整数N(N长度<20)划分为M(M>1)个部分,使这N个部分的乘积最大。N、M从键盘输入,输出最大值及一种划分方式。


    输入数据:
    第一行一个正整数T(T<=10000)。表示有T组数据。
    接下来T行每行两个正整数N,M。


    输出数据:
    对于每组数据
    第一行输出最大值。
    第二行输出划分方案,将N按顺序分成M个数输出,两个数之间用空格格开。


    例子
    输入文件:separate.in
    1
    199 2


    输出文件:separate.out
    171
    19 9


    WA的代码= =

    #include <cstdio>
    #include <string>
    #include <cstring>
    #include <algorithm>
    #define R1(i,n) for(register int i=1;i<=n;++i)
    #define R0(i,n) for(register int i=0;i<n;++i)
    #define r(i,s,t) for(register int i=s;i<=t;++i)
    #define  cl(a,m) memset(a,m,sizeof(a))
    using namespace std;
    template <class T> inline void read(T&x){
        bool f=false;char ch;
        for(ch=getchar();ch<=32;ch=getchar());
        if (ch=='-')f=true,ch=getchar();
        for(x=0;ch>32;ch=getchar()) x=x*10+ch-'0';
        if(f)x=-x;
    }
    template <class T> inline void write(T x){
        if(x<0)putchar('-'),x=-x;
        if(x<10)putchar(x + '0');
        else write(x / 10),putchar(x%10+'0');
    }
    template <class T> inline void writeln(T x){
        write(x);puts("");
    }
    void setIO(string t){
    string a=t+".in",b=t+".out";
    freopen(a.c_str(),"r",stdin);
    freopen(b.c_str(),"w",stdout);
    }
    long long g[500][500],f[500][500],v[500][500];char s[23];
    void print(int p,int d){
        if(d==0)return;
        print(g[p][d],d-1);
        r(i,g[p][d],p-1)write(s[i]-'0');
        putchar(' ');
    }
    
    int m,t;
    int main(){
        setIO("separate");
        read(t);
        while(t--){
            scanf("%s",s);
            read(m);
            int l=strlen(s);
            R1(i,l){
                int sum=0;
                r(j,i,l){
                    //if(s[j-1]>0)
                    sum=sum*10+s[j-1]-'0',
                    v[i][j]=sum;
                }
            }
            cl(f,-1);
            f[0][0]=1;
            R1(i,l)
            R1(j,min(i,m))
            R1(k,i){
                if(f[k-1][j-1]*v[k][i]>f[i][j]){
                    f[i][j]=f[k-1][j-1]*v[k][i];
                    g[i][j]=k-1;
                }
            }
            writeln(f[l][m]);
            print(l,m);
            puts("");
    
        }
        return 0;
    }

    快餐问题

    题目

    Peter近期在R市开了一家快餐店,为了招揽顾客,该快餐店准备推出一种套餐,该套餐由A个汉堡,B个薯条和C个饮料组成。价格廉价。为了提高产量,Peter从著名的麦当劳公司引进了N条生产线。全部的生产线都可以生产汉堡,薯条和饮料,因为每条生产线每天所能提供的生产时间是有限的、不同的,而汉堡。薯条和饮料的单位生产时间又不同。这使得Peter非常为难,不知道怎样安排生产才干使一天中生产的套餐产量最大。请你编一程序。计算一天中套餐的最大生产量。

    为简单起见,如果汉堡、薯条和饮料的日产量不超过100个。


    输入数据:
    第一行为三个不超过100的正整数A、B、C中间以一个空格分开。
    第二行为3个不超过100的正整数p1,p2,p3分别为汉堡。薯条和饮料的单位生产耗时。中间以一个空格分开。
    第三行为为一个整数N (0<=0<=10),表示有N条流水线
    第四行为N个不超过10000的正整数,当中Ti表示第i条生产流水线每天提供的生产时间,中间以一个空格分开。


    输出数据:
    仅一行,即每天套餐的最大产量。


    输入文件:meal.in
    2 2 2
    1 2 2
    2
    6 6


    输出文件:meal.out
    1


    代码

    #include <cstdio>
    #include <string>
    #include <algorithm>
    #define R1(i,n) for(register int i=1;i<=n;++i)
    using namespace std;
    template <class T> inline void read(T&x){
        bool f=false;char ch;
        for(ch=getchar();ch<=32;ch=getchar());
        if (ch=='-')f=true,ch=getchar();
        for(x=0;ch>32;ch=getchar()) x=x*10+ch-'0';
        if(f)x=-x;
    }
    template <class T> inline void write(T x){
        if(x<0)putchar('-'),x=-x;
        if(x<10)putchar(x + '0');
        else write(x / 10),putchar(x%10+'0');
    }
    template <class T> inline void writeln(T x){
        write(x);puts("");
    }
    void setIO(string t){
    string a=t+".in",b=t+".out";
    freopen(a.c_str(),"r",stdin);
    freopen(b.c_str(),"w",stdout);
    }
    int A,B,C,p1,p2,p3,n,t[20],ans;
    int f[20][101][101][101];
    int main(){
        setIO("meal");
        //f[i][a][b][c] :  前i条流水线, 生产a个汉堡,b个薯条,c个饮料的最大套餐产量
        read(A),read(B),read(C);
        read(p1),read(p2),read(p3);
        if(!p1 && !p2 && !p3){writeln(0);return 0;}
        read(n);
        R1(i,n)read(t[i]),t[i]+=t[i-1];
    //  R1(i,n)R1(j,n)R1(k,n)f[0][i][j][k]=0;
        R1(i,n)
            for(register int a=A;a*p1<=t[i]&&a<=100;++a)
                for(register int b=B;a*p1+b*p2<=t[i]&&b<=100;++b)
                    for(register int c=C;a*p1+b*p2+c*p3<=t[i]&&c<=100;++c){
                        ans=max(ans,f[i][a][b][c]=max(f[i][a-A][b-B][c-C]+1,max(f[i-1][a-A][b-B][c-C]+1,f[i][a][b][c])));
                        //if(f[i][a][b][c])printf("f[%d][%d][%d][%d] = %d
    ",i,a,b,c,f[i][a][b][c]);
                    }
    
    writeln(ans);
    }
    
    

    物品装箱问题

    题目

    设有n种物品,记作A1、A2、…、An,相应于每一个Ai(1<=i<=n)都有一个重量Awi和价值Avi(重量和价值都为正整数)。

    另外,相应于每一个Ai,都有一件可取代它的“代用品”Bi,Bi的重量和价值分别为Bwi和Bvi。


    本题的任务是:选择这n件物品或其代用品的一个子集装进背包,使总重量不超过给定重量TOT,同一时候使总价值VAL最高。装填的第I步,要么装入Ai。要么装入Bi,要么Ai和Bi都不装。


    输入数据:
    第一行:n TOT ,n<=100, TOT<=10000
    第二行:AW1 A v1 B W1 Bv1
    第三行:AW2 A v2 B W2 Bv2
    ……
    第n+1行:AWn A vn B Wn Bvn


    输入数据:
    仅仅有一个数为最大的价值


    输入文件:box.in
    4 20
    8 20 12 31
    2 3 9 20
    13 31 11 12
    8 9 13 36


    输出文件:box.out
    40


    分析

    01背包
    三选一乱搞

    代码

    #include <cstdio>
    #include <string>
    #include <algorithm>
    #define mn 200
    #define mt 10020
    #define R1(i,n) for(register int i=1;i<=n;++i)
    using namespace std;
    template <class T> inline void read(T&x){
        bool f=false;char ch;
        for(ch=getchar();ch<=32;ch=getchar());
        if (ch=='-')f=true,ch=getchar();
        for(x=0;ch>32;ch=getchar()) x=x*10+ch-'0';
        if(f)x=-x;
    }
    template <class T> inline void write(T x){
        if(x<0)putchar('-'),x=-x;
        if(x<10)putchar(x + '0');
        else write(x / 10),putchar(x%10+'0');
    }
    template <class T> inline void writeln(T x){
        write(x);puts("");
    }
    void setIO(string t){
    string a=t+".in",b=t+".out";
    freopen(a.c_str(),"r",stdin);
    freopen(b.c_str(),"w",stdout);
    }
    int n,tot;
    int f[mt],a_w[mn],a_v[mn],b_w[mn],b_v[mn];
    int main(){
        setIO("box");
        read(n),read(tot);
        R1(i,n)read(a_w[i]),read(a_v[i]),read(b_w[i]),read(b_v[i]);
        R1(i,n)for(register int j=tot;j>=min(a_w[i],b_w[i]);--j){
            f[j]=(j>=a_w[i]?

    max(f[j],f[j-a_w[i]]+a_v[i]):f[j]); f[j]=(j>=b_w[i]? max(f[j],f[j-b_w[i]]+b_v[i]):f[j]); } writeln(f[tot]); }





    又是颓废的一天= =
    队长又要喷我了orz

  • 相关阅读:
    算法之路——插入排序篇3:希尔排序
    对enum的探讨
    算法之路——插入排序篇1
    算法之路——快速排序
    算法之路——插入排序篇2
    圆的角度DDA算法初试
    解决omnicppcomplete显示"pattern not found"
    汇编
    直线的dda算法
    equ定义的是符号
  • 原文地址:https://www.cnblogs.com/wzjhoutai/p/7279642.html
Copyright © 2011-2022 走看看