区间DP,在我的初步理解是,在这个区间内部进行DP操作,得到一个最优解,这个区间是可以分割成小的区间,并且由小的区间合并到大的区间

括号匹配

给定一个区间,问子序列中,成对匹配的子序列最长是多少。

首先区间DP应该先写出动态转移方程,

首先应该预处理,假设括号不匹配,那么状态转移

DP[i][j]=DP[i+1][j];

如果S[i]和S[k]成功匹配,我们转移是从两边转移

DP[i][j]=MAX(DP[i][j],DP[i][K-1]+DP[K+1][j]+2);

代码:

#include<iostream>

#include<stdio.h>

#include<string.h>

using namespace std;

char s[103];

int dp[103][103];

int main(){

 

  while(scanf("%s",s+1) && s[1]!='e'){

 

    int len=strlen(s+1);

    memset(dp,0,sizeof(dp));

    for (int i=len-1;i>=1;i--)//左边间

        for (int j=i+1;j<=len;j++)//右边界

        {

           dp[i][j]=dp[i+1][j];//z假设他不匹配那么dp[i+1][j]只能由dp[i][j]推出

           for (int k=i+1;k<=j;k++)

           {

               if ((s[i]=='(' && s[k]==')') || (s[i]=='[' && s[k]==']'))//匹配成功

                  dp[i][j] = max(dp[i][j],dp[i+1][k-1]+dp[k+1][j]+2);//转移方程

           }

        }

      printf("%d\n",dp[1][len]);

  }

  return 0;

}

合并石子

给你N堆石子,只能合并相邻的石子,并且花费为两堆石子权值之和,求合成一堆所需费用。

 

分析:

一般对于这种DP给定区间求最小值,首先应该初始化INF.

我们来分析一下这个DP,这是区间DP最基础的类型,我们首先应该分析这个DP应该是二维的,因为只有一段,所以可以很容易写出DP转移方程

  DP[i][j]代表,在i,j范围内合并所需要的最小权值,而K作为分割,在i->j里面遍历,而SUM[i]][j]为石头的权值,表示合并i->k->j所需要的权值

  Sum[i][j]=Sum[i][k]+Sum[k][j];

  DP[i][j]=max( DP[i][j] , DP[i][k]+DP[k+1][j]+sum[i][j] );

代码:

#include<iostream>

#include<stdio.h>

#include<string.h>

#define INF 0x3f3f3f3f

using namespace std;

int main(){

   int n;

   int dp[205][205];

   int sum[205][205];//石头数量

   int a[205];

   while(~scanf("%d",&n)){

      memset(dp,0,sizeof(dp));

      memset(sum,0,sizeof(sum));

      for(int i=1;i<=n;i++){

         scanf("%d",&a[i]);

         sum[i][i]=a[i];

      }

 

      for (int i=1;i<=n;i++)

        for (int j=1;j<=n;j++){

         dp[i][j]= i==j? 0 : INF;//初始化操作

      }

      for (int len=1;len<n;len++){//首先枚举每个长度

         for (int i=1;i+len<=n;i++){//再枚举每个初始点

            int j=len+i;//结束点

            for (int k=i;k<j;k++){//分割点

                sum[i][j]=sum[i][k]+sum[k+1][j];

                dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[i][j]);

            }

         }

      }

      cout<<dp[1][n]<<endl;

   }

  return 0;

}

总结:区间DP的DP方程其实并不难写

大概就是DP[i][j]=MAX/MIN(DP[i][j],DP[i][k]+DP[k][j]+w);

W代表这样合并的影响