zoukankan      html  css  js  c++  java
  • 区间DP入门

    石子归并

     51Nod - 1021 

    N堆石子摆成一条线。现要将石子有次序地合并成一堆。规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的代价。计算将N堆石子合并成一堆的最小代价。
     
    例如: 1 2 3 4,有不少合并方法
    1 2 3 4 => 3 3 4(3) => 6 4(9) => 10(19)
    1 2 3 4 => 1 5 4(5) => 1 9(14) => 10(24)
    1 2 3 4 => 1 2 7(7) => 3 7(10) => 10(20)
     
    括号里面为总代价可以看出,第一种方法的代价最低,现在给出n堆石子的数量,计算最小合并代价。
     

    Input第1行:N(2 <= N <= 100) 
    第2 - N + 1:N堆石子的数量(1 <= Aii <= 10000)Output输出最小合并代价Sample Input

    4
    1
    2
    3
    4

    Sample Output

    19
    题解:区间dp入门题,dp[i][j]表示从第i堆石子到第j堆石子合并的最小代价。区间dp一般都是从小区间开始求得最优解然后扩展到大的区间,而求大区间的最优解的时候用到的小区间的最优解已经求过,所以直接拿来用即可。
    所以说区间动规一般都是三层for循环, 前两层用来控制区间长度, 最后一层用来枚举最后一次的位置, 还有需要注意的是区间用从小到大, 因为动态规划就是后面的用到前面的出的结果递推后面的结果。
    1 //合并i到j的所有石子。那前一状态一定是两堆石子。
    2 //这步我们就枚举所有可能的位置(两堆石子分开的位置)  
    3 for(int k = i; k < j; k++)
    4  {
    5      if(dp[i][j] > dp[i][k] + dp[k+1][j] + sum[i][j])
    6          dp[i][j] = dp[i][k] + dp[k+1][j] + sum[i][j];
    7  }

    4个数(1,2,3,4) 
    某区间(i到j)相距为1时 d = 1 可求出f[1][2] = 3; f[2][3] = 5; f[3][4] = 7; 
    d = 2时 , f[1][3] = min(f[1][2] + f[3][3], f[1][1] + f[2][3])+sum[1][3]= 9; (这里f[3][3] = 0,应为合并自己没花费)。同理f[2][4] = 14; 
    d = 3时:f[1][4] = 19; 
    枚举前一状态 f[1][4] = min(f[1][1]+f[2][4], f[1][2]+f[3][4], f[1][3] + f[4][4]) + sum[1][4];到这有点眉目没。

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #define min(a,b) a<b?a:b
     5 #define max(a,b) a>b?a:b
     6 #define inf 0x3f3f3f3f
     7 using namespace std;
     8 const int maxn=110;
     9 int n;
    10 int a[maxn];
    11 int sum[maxn];
    12 int dp[maxn][maxn];
    13 int main()
    14 {
    15     cin>>n;
    16     for(int i=1;i<=n;i++)
    17     {
    18         scanf("%d",&a[i]);
    19         sum[i]=sum[i-1]+a[i];
    20     }
    21     memset(dp,0,sizeof(dp));
    22     for(int len=2;len<=n;len++)
    23     {
    24         for(int i=1;i<=n-len+1;i++)
    25         {
    26             int j=i+len-1;
    27             dp[i][j]=inf;
    28             for(int k=i;k<j;k++)
    29             {
    30                 dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]);
    31             }
    32         }
    33     }
    34     printf("%d
    ",dp[1][n]);
    35     return 0;
    36 }

    Multiplication Puzzle

     POJ - 1651

    The multiplication puzzle is played with a row of cards, each containing a single positive integer. During the move player takes one card out of the row and scores the number of points equal to the product of the number on the card taken and the numbers on the cards on the left and on the right of it. It is not allowed to take out the first and the last card in the row. After the final move, only two cards are left in the row. 

    The goal is to take cards in such order as to minimize the total number of scored points. 

    For example, if cards in the row contain numbers 10 1 50 20 5, player might take a card with 1, then 20 and 50, scoring 
    10*1*50 + 50*20*5 + 10*50*5 = 500+5000+2500 = 8000

    If he would take the cards in the opposite order, i.e. 50, then 20, then 1, the score would be 
    1*50*20 + 1*20*5 + 10*1*5 = 1000+100+50 = 1150.

    Input

    The first line of the input contains the number of cards N (3 <= N <= 100). The second line contains N integers in the range from 1 to 100, separated by spaces.

    Output

    Output must contain a single integer - the minimal score.

    Sample Input

    6
    10 1 50 50 20 5
    

    Sample Output

    3650

    题意:是n个数相乘,每次从中抽取一个数出来与相邻两个数相乘,直到抽到只剩两个数字,第一个数和最后一个数不能抽。

    题解:和上一个题套路基本一致,大概框架为三个for循环,第一层for循环遍历区间长度,第二层for循环遍历区间的起始点i,以及终止点用j表示,第三层for循环遍历断点。就此题而言,len从3开始,表示区间长度最短为3, dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]+a[i]*a[j]*a[k])为核心,例如i=1 j=7 k=5表示[1,7]中,最后剩下的三个数为a[1],a[5],a[7],下一步的操作为拿掉a[5],总代价加上a[1]*a[5]*a[7],可以进行这步操作的前提是a[2]到a[5]中只剩下a[5],a[6]到a[7]中也只剩下a[7],及前面dp[1][5]早已求出,后面的dp[5][7]也早就求出,所以求dp[1][7]在以5为断点时的值就是dp[1][7]=min(dp[1][7],dp[1][5]+dp[5][7]+a[1]*a[5]*a[7])

    上代码:

     

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #define min(a,b) a<b?a:b
     5 #define inf 0x3f3f3f3f
     6 using namespace std;
     7 const int maxn=110;
     8 int dp[maxn][maxn];
     9 int a[maxn];
    10 int n;
    11 int main()
    12 {
    13     cin>>n;
    14     for(int i=1;i<=n;i++)
    15     {
    16         scanf("%d",&a[i]);
    17     }
    18     memset(dp,0,sizeof(dp));
    19     for(int len=3;len<=n;len++)
    20     {
    21         for(int i=1;i<=n-len+1;i++)
    22         {
    23             int j=i+len-1;
    24             dp[i][j]=inf;
    25             //cout<<i<<" "<<j<<endl;
    26             for(int k=i;k<j;k++)
    27             {
    28                 dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]+a[i]*a[j]*a[k]);
    29             }
    30         }
    31     }
    32     printf("%d
    ",dp[1][n]);
    33 }

     

    好啦,今天任务完成,去吃饭饭啦~~~耶耶耶!!!


     
  • 相关阅读:
    容易遗忘的配置
    linux中启动Zookeeper
    Linux中设置静态ip地址
    IDEA中工程上传到SVN
    Invalid bound statement(not found):cn.e3mall.mapper.TbItemMapper.selectByExample.....
    获取不到jdbc.driver的值解决办法
    idea中applicationContext-trans.xml中的Cannot resolve bean 'dataSource'...的问题解决
    idea中applicationContext-dao.xml文件中Cannot resolve file***** :spring xml model validation问题
    如何在IDEA中导入一个普通的java工程
    Navicate for mysql如何导入一个sql文件
  • 原文地址:https://www.cnblogs.com/1013star/p/9755804.html
Copyright © 2011-2022 走看看