zoukankan      html  css  js  c++  java
  • 回顾一些较简单的dp题

    1.导弹拦截  (+贪心)

      两问:一个导弹拦截系统最多能拦多少导弹 要拦截所有导弹至少需要多少拦截系统

      第一问感觉是一个比较巧妙的方法:

        维护一个单调递减的序列 length[] 记录的是拦截导弹的高度

        当下一个导弹小于 length[] 最后一个数(最小的数)则直接把它加在序列后即可

        若大于 则找到序列中比它大的最小的数(二分)然后替换 可以保证最优

      第二问 就是贪心啊

        当现有的导弹系统的拦截高度都小于当前导弹的高度 则开一个新的系统

        否则找到拦截高度比导弹高度高的最小的系统来拦截

        这里记录系统拦截高度的数组一定是单调递增的无需排序

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int x;
    bool f;
    int height[100010],length[100010],minh[100010];
    int main()
    {
        int y=1;
        while(scanf("%d",&height[y])==1) y++;y--;
        length[1]=height[1];
        int top=1;
        for(int i=2;i<=y;i++)
        {
            if(height[i]<=length[top]) length[++top]=height[i];
            else
            {
                int left=1,right=top,ans;
                while(left<=right)
                {
                    int mid=(left+right)/2;
                    if(length[mid]<height[i])
                    {
                        ans=mid;
                        right=mid-1;
                    }
                    else left=mid+1;
                }
                length[ans]=height[i];
            }
        }  
        cout<<top<<endl;
        int maxa=0;
        for(int i=1;i<=y;i++)
        if(maxa<length[i]) maxa=length[i];
        int num=1;minh[1]=height[1];
        for(int i=2;i<=y;i++)
        {
            f=0;
            for(int j=1;j<=num;j++)
             if(height[i]<=minh[j]) {minh[j]=height[i];f=1;break;}
            if(f==0) minh[++num]=height[i];
        }
        cout<<num;
        return 0;
    }
    View Code

    2.石子合并 (+断环为链法)

      区间dp一般套路:枚举起点 枚举区间长度(或终点) 枚举断点 转移

      注意枚举的顺序要保证由已知推未知

      很多时候遇到环都可能要断环为链(图论也是这样)

     1 #include<iostream>
     2 using namespace std;
     3 int a[210];
     4 int s[210];
     5 int ans1[210][210];
     6 int ans2[210][210];
     7 int main()
     8 {
     9     int n;
    10     cin>>n;
    11     for(int i=1;i<=n;i++)
    12     {
    13         cin>>a[i];
    14         s[i]=s[i-1]+a[i];
    15         a[i+n]=a[i];
    16     }
    17     for(int i=n+1;i<=n*2;i++)
    18     s[i]=s[i-1]+a[i];
    19     for(int i=1;i<=2*n;i++)
    20     for(int j=1;j<=2*n;j++)
    21     if(j!=i) ans2[i][j]=2100000;
    22     for(int h=1;h<=n;h++)
    23     {
    24         for(int i=h+n-1;i>=h;i--)
    25         {
    26             for(int j=i;j<=h+n-1;j++)
    27             {
    28                 for(int k=i+1;k<=j;k++)
    29                 {
    30                     ans1[i][j]=max(ans1[i][j],ans1[i][k-1]+ans1[k][j]+s[j]-s[i-1]);
    31                     ans2[i][j]=min(ans2[i][j],ans2[i][k-1]+ans2[k][j]+s[j]-s[i-1]);
    32                 }
    33             }
    34         }
    35     }
    36     int maxn,minn=2100000;
    37     for(int i=1;i<=n;i++)
    38     {
    39         maxn=max(maxn,ans1[i][i+n-1]);
    40         minn=min(minn,ans2[i][i+n-1]);
    41     }
    42     cout<<minn<<endl<<maxn<<endl;
    43     return 0;
    44 } 
    View Code

    3.相似基因 

      现在看起来好像很显然的样子

      f[i][j] 表示第一个字符串匹配到第i位 第二个字符串匹配到第j位最大的相似度

      三种情况转移 分别是在第一个,第二个字符串加空碱基 不加空碱基

      注意初始化

     1 #include<iostream>
     2 #include<cstdio>
     3 using namespace std;
     4 int len1,len2,sum;
     5 char s1[110],s2[110];
     6 int a1[110],a2[110];
     7 char ch;
     8 int f[110][110];
     9 int s[6][6]={{0,0,0,0,0,0},
    10              {0,5,-1,-2,-1,-3},
    11              {0,-1,5,-3,-2,-4},
    12              {0,-2,-3,5,-2,-2},
    13              {0,-1,-2,-2,5,-1},
    14              {0,-3,-4,-2,-1,0}};
    15 int change(char x)
    16 {
    17     if(x=='A') return 1;
    18     else if(x=='C') return 2;
    19     else if(x=='G') return 3;
    20     else if(x=='T') return 4;
    21 }
    22 int main()
    23 {
    24     scanf("%d",&len1);ch=getchar();
    25     for(int i=1;i<=len1;i++) scanf("%c",&s1[i]);        
    26     scanf("%d",&len2);ch=getchar();
    27     for(int i=1;i<=len2;i++) scanf("%c",&s2[i]);
    28     for(int i=1;i<=len1;i++) a1[i]=change(s1[i]);
    29     for(int i=1;i<=len2;i++) a2[i]=change(s2[i]);
    30     for(int i=1;i<=len1;i++)
    31         for(int j=1;j<=len2;j++) f[i][j]=-21000000;
    32     for(int i=1;i<=len1;i++) f[i][0]=f[i-1][0]+s[a1[i]][5];
    33     for(int i=1;i<=len2;i++) f[0][i]=f[0][i-1]+s[a2[i]][5];
    34     for(int i=1;i<=len1;i++)
    35     {
    36         for(int j=1;j<=len2;j++)
    37         {
    38             f[i][j]=max(f[i][j],f[i-1][j]+s[a1[i]][5]);
    39             f[i][j]=max(f[i][j],f[i][j-1]+s[a2[j]][5]);
    40             f[i][j]=max(f[i][j],f[i-1][j-1]+s[a1[i]][a2[j]]);
    41         }
    42     }
    43     printf("%d",f[len1][len2]);
    44     return 0;
    45 }
    View Code

    4.传纸条(优化维度)

      四维dp 优化成三维

     1 #include<iostream>
     2 #include<cstdio>
     3 using namespace std;
     4 int read()
     5 {
     6     int ans=0;char c;
     7     c=getchar();
     8     while(c<'0'||c>'9') c=getchar();
     9     while(c>='0'&&c<='9') {ans=ans*10+c-'0';c=getchar();}
    10     return ans;
    11 }
    12 int f[1010][510][510];
    13 int a[510][510];
    14 int main()
    15 {
    16     int m=read(),n=read();
    17     for(int i=1;i<=m;i++)
    18     for(int j=1;j<=n;j++)
    19     a[i][j]=read();
    20     for(int k=1;k<=n+m;k++)
    21     {
    22         for(int i=1;i<=n;i++)
    23         {
    24             for(int j=1;j<=n;j++)
    25             {
    26                 if(k-i+1<1||k-j+1<1) continue;
    27                 f[k][i][j]=max(max(max(f[k-1][i][j],f[k-1][i-1][j]),f[k-1][i][j-1]),f[k-1][i-1][j-1]);
    28                 f[k][i][j]+=a[k-i][i]+a[k-j][j];
    29                 if(i==j) f[k][i][j]-=a[k-i][i];
    30             }
    31         }
    32     }
    33     cout<<f[m+n][n][n];
    34     return 0;
    35 } 
    View Code

    5.花店橱窗布置

      这一题要输出最优方案 所以f[i][j]表示的是前i束花放在前j个瓶子里 且第i束花放在第j个瓶子里的最大美学值

     1 #include<iostream>
     2 using namespace std;
     3 int a[110][110];  //a[i][j] 第i束花放在第j个花瓶中的美学值
     4 int b[110][110];  //b[i][j] 前i束花放在前j个花瓶中的最大美学值 
     5 int c[110][110],d[110];
     6 int main()
     7 {
     8     int f,v;
     9     cin>>f>>v;
    10     for(int i=1;i<=f;i++)
    11     for(int j=1;j<=v;j++)
    12     cin>>a[i][j];
    13     //for(int i=1;i<=v-f+1;i++) b[1][i]=a[1][i];
    14     for(int i=1;i<=f;i++)
    15     for(int j=1;j<=v;j++)
    16     b[i][j]=-2100000000; 
    17     /*如果b数组中初始值都为0
    18     那么当第一束花放在前几个花瓶中美学值为负数时就会出错;
    19     或:直接初始化第一束花放在前几个花瓶中的美学值(前面被注释掉的)
    20     但注意此时后面一个循环的i从2开始*/ 
    21        
    22     for(int i=1;i<=f;i++)
    23     for(int j=i;j<=v-f+i;j++) //j<=v-f+i!!!
    24     for(int k=i-1;k<=j-1;k++)
    25     {
    26         if(b[i][j]<b[i-1][k]+a[i][j])
    27         {
    28             b[i][j]=b[i-1][k]+a[i][j];
    29             c[i][j]=k;
    30         }
    31     }
    32     int maxn=-2100000000,k;
    33     for(int i=f;i<=v;i++)
    34     {
    35         if(b[f][i]>maxn)
    36         {
    37             maxn=b[f][i];
    38             k=i;
    39         }
    40     }
    41     cout<<maxn<<endl;
    42     for(int i=1;i<=f;i++)
    43     {
    44         d[i]=k;
    45         k=c[f-i+1][k];
    46     }
    47     for(int j=f;j>=1;j--) cout<<d[j]<<" ";
    48     return 0; 
    49 }
    View Code

    6.编辑距离

      和3类似

     1 #include<iostream>
     2 #include<cstring> 
     3 #include<cstdio>
     4 using namespace std;
     5 char a[2010],b[2010];
     6 int f[2010][2010];
     7 int main()
     8 {
     9     int m,n,i,j;
    10     scanf("%s%s",a,b);
    11     m=strlen(a);n=strlen(b);
    12     for(int i=m+1;i>=1;i--) a[i]=a[i-1];
    13     for(int j=n+1;j>=1;j--) b[j]=b[j-1]; 
    14     for(i=1;i<=m;i++) f[i][0]=i;
    15     for(j=1;j<=n;j++) f[0][j]=j;
    16     for(i=1;i<=m;i++)
    17     {
    18         for(j=1;j<=n;j++)
    19         {
    20             if(a[i]==b[j]) f[i][j]=f[i-1][j-1];
    21             else
    22             {
    23                 f[i][j]=min(min(f[i-1][j-1],f[i-1][j]),f[i][j-1])+1;
    24             }
    25         }
    26     }
    27     cout<<f[m][n];
    28     return 0;
    29 }
    View Code

    7.乘积最大

      f[i][j] 表示到第i位数已经加了j个乘号的最大乘积

      加高精有点麻烦啊

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<string>
     5 #define rg register
     6 #define M 110
     7 using namespace std;
     8 int read()
     9 {
    10   int x=0,y=1;char c;
    11   c=getchar();
    12   while(c<'0'||c>'9') {if(c=='-') y=-1;c=getchar();}
    13   while(c>='0'&&c<='9') {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
    14   return x*y;
    15 }
    16 string ss;
    17 int n1,k1;
    18 int a[M];
    19 struct node
    20 {
    21   int s[M];
    22   int len;
    23 }f[10][M];
    24 node calc(node x,int l,int r)
    25 {
    26   node x1,y1;y1.len=r-l+1;
    27   int len1=x.len,len2=y1.len,len=len1+len2-1;
    28   memset(x1.s,0,sizeof(x1.s));
    29   memset(y1.s,0,sizeof(y1.s));
    30   for(rg int i=r;i>=l;i--) y1.s[r-i+1]=a[i];
    31   for(rg int i=1;i<=len1;i++)
    32     for(rg int j=1;j<=len2;j++)
    33       x1.s[i+j-1]+=x.s[i]*y1.s[j];
    34   for(rg int i=1;i<=len;i++)
    35     {
    36       x1.s[i+1]+=x1.s[i]/10;
    37       x1.s[i]%=10;
    38     }
    39   if(x1.s[len+1]) len++;
    40   x1.len=len;
    41   return x1;
    42 }
    43 node cmp(node x,node y)
    44 {
    45   int len1=x.len,len2=y.len;
    46   if(len1<len2) return y;
    47   if(len1>len2) return x;
    48   for(rg int i=len1;i>=1;i--)
    49     {
    50       if(x.s[i]>y.s[i]) return x;
    51       if(x.s[i]<y.s[i]) return y;
    52     }
    53   return y;
    54 }
    55 int main()
    56 {
    57   n1=read();k1=read();
    58   cin>>ss;
    59   for(int i=1;i<=n1;i++) a[i]=ss[i-1]-'0';
    60   for(int i=1;i<=n1;i++)
    61     for(int j=i;j>=1;j--)
    62       f[0][i].s[++f[0][i].len]=a[j];
    63   for(int i=2;i<=n1;i++) //前i个数
    64     {
    65       int maxn=min(i-1,k1);
    66       for(int k=1;k<=maxn;k++)//k个乘号
    67       for(int j=k;j<i;j++)//第k个乘号放哪
    68       f[k][i]=cmp(f[k][i],calc(f[k-1][j],j+1,i));
    69     }
    70    for(int i=f[k1][n1].len;i>=1;i--)
    71     printf("%d",f[k1][n1].s[i]);
    72       return 0;
    73 }
    View Code
    光伴随的阴影
  • 相关阅读:
    C++学习笔记(十六):友元
    C++学习笔记(十五):异常
    C++学习笔记(十四):模板
    C++学习笔记(十三):类、包和接口
    C++学习笔记(十二):类继承、虚函数、纯虚函数、抽象类和嵌套类
    C++学习笔记(十一):void*指针、类型转换和动态内存分配
    C++学习笔记(十):类
    quartz 实现调度任务 SchedulerManager
    Session 活化与钝化 与tomcat钝化驱动器
    web listener
  • 原文地址:https://www.cnblogs.com/forward777/p/10336200.html
Copyright © 2011-2022 走看看