zoukankan      html  css  js  c++  java
  • 动态规划学习记录

    首先是入门级别的一维dp。

    这个是凑硬币,如果我们有面值为1元、3元和5元的硬币若干枚,如何用最少的硬币凑够11元?

    动态规划算法的核心是:每个子问题的状态和状态的转移方程。

    状态是:dp[i] ,即凑够i元最少需要的硬币的个数

    转移方程是:dp[i] = min(dp[i-C 1 ]+1,dp[i-C 2 ]+1,dp[i-C 3 ]+1,……,dp[i-C j ]+1])

    即,每个状态的值都是最小的那个。

    #include<stdio.h>
    #define min(a,b) a<b?a:b
    int main()
    {
    int c[3]={1,3,5};
    int dp[100], i , j , k=999, n;
    scanf("%d",&n);
    dp[0] = 0;
    for( i = 1 ;i <= n ; i++)
    { k = 999;//这里是关键,每次都要重新赋值。
    for(j = 0 ; j < 3; j++)//把每种硬币的可能都找一遍
    if(i >= c[j])
    {
    k = min(dp[i-c[j]]+1,k);
    // printf("%d %d ",k ,c[j]);
    //这是从三种硬币中找出最小硬币数的那个。
    //dp中的数值是,到这个i的硬币数
    }
    dp[i]=k;
    //printf("%d ",k);
    //每次循环之后min都是最小的硬币数。
    //这时无法区分他是用怎么的硬币构成
    }

    for( i = 0 ;i <= n ; i ++)
    printf("%d元至少要%d个硬币 ", i, dp[i]);

    }

    下一题是lis就是最长非降子序列    longest increasing subsequence

    5 3 4 8 6 7 找这个序列的   最长非降子序列

    很明显是 3 4 6 7 这个最长 那么算法是要怎么找呢?

    前1个数的lis长度 dp(1)= 1;   序列    5

    前2个数的lis长度 dp(2)= 1;   序列    3   优先选小的  ,3前面没有比3小的了

    前3个数的lis长度 dp(3)= 2;   序列    3,4   dp(3) = dp(2) + 1 

    前4个数的lis长度 dp(4)= 3;   序列    3,4,8  8前面3个都比他小,因此要判断 

                       dp(4)= max(dp(1),dp(2),dp(3))                    +1=3 

    前5个数的lis长度 dp(5)= 3;   序列    3,4,6这个同上

    前6个数的lis长度 dp(6)= 4;   序列    3,4,6,7 这个也是dp(6)=max(dp(4),                      dp(5))+1

    所以要求dp(i),就把i之前的每一个子序列中,最后一个数不大于a【i】的序列长度+1  然后取出最大的长度就是dp(i); 如果i前面的各个子序列都大于a【i】,那么他就dp(i) = 1 ;

    #include <iostream>
    using namespace std;
    int d[100];
    int lis(int a[], int n)
    {
    int len = 1, i, j;
    for(i = 0 ; i < n ; i++)
    {//查询每一位置
    d[i] = 1;
    for(j = 0 ; j < i; j++)
    //在当前位置之前的每一个位置
    if(a[j] <= a[i] && d[j]+1 > d[i])
    //把前面各个子序列中最后一个数不大于a【i】
    d[i] = d[j] + 1;
    //反复覆盖一个位置,
    if(d[i] > len) len = d[i];
    //每次留下最大的长度
    }
    return len;
    }
    int main()
    {
    int a[100],m,t,i;
    cin>>m;

    for(i = 0 ; i <m ; i++)
    cin>>a[i];

    cout << lis(a,m)<<endl;
    return 0;
    }

    现在提升难度来个二维的dp  

    找苹果

    平面上有m*m个格子,每个格子中放着一定数量的苹果。你从左上角的格子开始,每一步只能向下走或是向右走,每次走到一个格子上就把格子里的苹果收集起来,这样下去,你最多能收集到多少个苹果。

    先来找找状态  每个格子只能从左边和上面下来,要知道这个位置的最大总苹果就判断上面和左边的苹果哪个大,从大的那边走,然后就是递归的来每一个找一遍。

    难度不大。思维掌握就好了。

    #include<stdio.h>
    #define max(a,b) a > b ? a : b
    int main()
    {
    int a[10][10] = {0},s[10][10] = {0};//数组最好大点
    int n,m,i,j;
    scanf("%d",&m);//正方形
    for(i = 0 ; i < m; i ++)
    for(j = 0 ; j < m ; j ++)
    scanf("%d",&a[i][j]);
    s[0][0]=a[0][0];
    for(i = 1 ; i < m ; i++)
    s[i][0] = a[i][0]+s[i-1][0];
    for(j = 1 ; j < m ; j++)
    s[0][j] = a[0][j]+s[0][j-1];
    //这两个for是为了防止溢出先把边缘的计算出来。
    for(i = 1 ; i < m ; i++)
    for(j = 1 ; j < m ; j++)
    {
    s[i][j] = max(s[i-1][j],s[i][j-1]);
    //这里是个坑,我也不知道为什么两个一起写就出错,
    s[i][j] += a[i][j];
    //分开就对了
    //逻辑也简单就是判断上面和左边哪一个大,选大的一个
    }

    for(i = 0 ; i < m; i ++)
    {
    for(j = 0 ; j < m ; j ++)
    printf("%d ",s[i][j]);
    printf(" ");
    }

    }

     数塔问题或者掉馅饼

    有如下所示的数塔,要求从顶层走到底层,若每一步只能走到相邻的结点,则经过的结点的数字之和最大是多少?

    1
    5
    7
    3 8
    8 1 0
    2 7 4 4
    4 5 2 6 5
    输出
    30
     1 #include <stdio.h>
     2 #include<stdio.h>
     3 #include<string.h>
     4 #define max(a,b,c)     (a>b?a:b)>c ? (a>b?a:b) : c
     5 #define P 100001
     6 int a[P][13];
     7 int main()
     8 {
     9     int n;
    10     while(scanf("%d",&n)!=EOF&&n)
    11     {
    12         int i,p,t,k,j=-1;
    13         memset(a,0,13*P*sizeof(int));
    14         for(i=0;i<n;i++)
    15          {
    16              scanf("%d%d",&p,&t);
    17              a[t][p+1]++;         /*位置后移一位*/
    18              if(t>j)   j=t;           /*记录最大时间*/
    19          }
    20          for(i=j-1;i>=0;i--)       /*最终时间肯定是连续的1到j,(1到j,推断理解),(j到1,敲代码)*/
    21          {
    22              for(k=1;k<=11;k++)
    23                 a[i][k]+=max(a[i+1][k-1],a[i+1][k],a[i+1][k+1]);   /*位置后移1位和数组开大2位的好处,k-1和k+1不会越界*/
    24          }//每次和后面一行对应的上面的三个数比较最大的
    25          printf("%d
    ",a[0][6]);
    26      }
    27      return 0;
    28  }

    思路嘛,还是一样,建立一个二维的状态表,每次往上面找,,不断用最好的来替换过去。。最后的结果就是最好的。

    下面来个比较难一些的,叫矩形嵌套:

    有n个矩形,每个矩形可以用a,b来描述,表示长和宽。矩形X(a,b)可以嵌套在矩形Y(c,d)中当且仅当a<c,b<d或者b<c,a<d(相当于旋转X90度)。例如(1,5)可以嵌套在(6,2)内,但不能嵌套在(3,4)中。你的任务是选出尽可能多的矩形排成一行,使得除最后一个外,每一个矩形都可以嵌套在下一个矩形内。

    http://acm.pdsu.edu.cn/problem.php?id=1171

    第一行是一个正正数N(0<N<10),表示测试数据组数,
    每组测试数据的第一行是一个正正数n,表示该组测试数据中含有矩形的个数(n<=1000)
    随后的n行,每行有两个数a,b(0<a,b<100。提示: (1,2)可以嵌套在(2,2)中,但不能嵌套在(2,1)中。),表示矩形的长和宽

    1
    4
    8 14
    16 28
    29 12
    14 8
    输出2
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<math.h>
    int cmp(const void *a,const void *b)
    {
        int* c = (int *)a;
        int* d = (int *)b;
        if(*c != *d)
           return *c - *d;
        return *(d+1) - *(c+1);
    }
    //二维排序,。
    
    int main()
    {
        int a[1010][5] ,b[1010],t,n,i,j,temp;
        scanf("%d",&t);
        while(t--)
        {
              scanf("%d",&n);
              for(i=0;i<n;i++)
              {
                   scanf("%d%d",&a[i][0],&a[i][1]);
                   if(a[i][0] > a[i][1])
                   {
                      temp = a[i][0];
                      a[i][0] = a[i][1];
                      a[i][1] =temp;
                   }
             }//输入
              qsort(a,n,sizeof(a[0]),cmp);
              int max=0;
              for(i=0;i<n;i++)
              {     max = 0;
                    for(j=i-1;j>=0;j--)
                    {
                        if(a[j][1]<a[i][1] && b[j]>max)
                           max = b[j];
                    }
                    b[i] = max + 1;
              }
              //dp的写状态
              int count = 0;
              for(i=0;i<n;i++)
                 if(b[i] > count)
                    count = b[i];
                //找最大值
              printf("%d
    ",count);
        }
        return 0;
    }
    

      



        

  • 相关阅读:
    springBoot异常处理
    webSocket
    Java正则
    String.format
    JSTL-taglib
    http meta
    chrome 常用插件下载安装
    mysql 命令行个性化设置
    Entity Framework Code First
    SignalR Connection has not been fully initialized
  • 原文地址:https://www.cnblogs.com/luyi14/p/4344946.html
Copyright © 2011-2022 走看看