QBXT 2018春季DP&图论班 2018.5.3 --- 区间DP专题

本文题目等来自北京大学张浩威学长的PPT。

1.区间DP:解决有关两个或以上的区间的合并或删除的问题(最大/小次数/价值、方案总数、可行性等)。

2.石子合并:

状态:dp[l][r]表示只考虑区间l~r的石子,将它们合并的最小代价。

状态转移:dp[l][r]=min{dp[l][r],dp[l][k]+dp[k+1][r]+s[r]-s[l-1]}

l~r这一堆石子可以分为l~k和k+1~r两堆石子,只考虑两堆石子时各自最小代价和加上将这两堆石子合并的代价和,这个可以用前缀和优化。

边界:dp[i][i]=0 只有一堆石子时不用合并,代价为0。

代码实现:

for(int len=1;len<n;len++)//枚举区间长度,注意取值范围
  for(int l=1;l<=n-len;l++) //枚举左端点
  {  
    int r=l+len;//右端点
    dp[l][r]=INF;
    for(int k=l;k<r;k++) {
      dp[l][r]=min(dp[l][r],dp[l][k]+dp[k+1][r]+s[r]-s[l-1]);
    }
  }

还有一种倒序枚举左端点,正序枚举右端点的做法,也能够保证状态转移合法,但不太直观。

石子合并  这道题可以用四边形不等式优化,然而据说很难理解 ,此处呈上zhw的代码,证明略。

for (len=1; len<n; len++) len左端点和右端点的差值
  for (l=1; l<=n-len; l++)
  {
    r=l+len; 
    dp[l][r]=INF;
    for (k=f[l][r-1]; k<=f[l+1][r]; k++)
      if (dp[l][k]+dp[k+1][r]+s[r]-s[l-1]<dp[l][r])
      {
        dp[l][r]=dp[l][k]+dp[k+1][r]+s[r]-s[l-1];
        f[l][r]=k;
      } 
  }

3.石子合并+

有n堆石子排成一排,第i堆石子的个数为ai。
每次可以将相邻2~3堆合并成一堆。
合并的代价为这2/3堆石子的石子个数之和。
设计方案要求代价之和最小。
同上题,枚举两个断点,该一下转移方程,再for一for就A了。

for (l=1; l<=n; l++) dp[l][l]=0;
for (len=1; len<n; len++) len左端点和右端点的差值
  for (l=1; l<=n-len; l++)
  {
    r=l+len; 
    dp[l][r]=INF;
    for (k=l; k<r; k++)
      dp[l][r]=min(dp[l][r],dp[l][k]+dp[k+1][r]+s[r]-s[l-1]);
    for (k=l; k<r; k++)
      for (t=k+1; t<r; t++)
        dp[l][r]=min(dp[l][r],dp[l][k]+dp[k+1][t]+dp[t+1][r]+s[r]-s[l-1]);
  }

4.石子合并++(?)

有n堆石子排成一排,第i堆石子的个数为ai。
每次可以将相邻2~n堆合并成一堆。
合并的代价为这2/3/.../n堆石子的石子个数之和。
设计方案要求代价之和最小。

思维题。。。直接一次性把n堆合成一堆即可。

5.加分二叉树

6.hihocoder1110 正则表达式

给定一个字符串,判断其是否为合法的正则表达式。
 一个正则表达式定义为:
 1:0是正则表达式,1也是正则表达式。
 2:P和Q都是正则表达式,则PQ是正则表达式。
 3:P是正则表达式,则(P)是正则表达式
 4:P是正则表达式,则P*也是正则表达式
 5:P和Q都是正则表达式,则P|Q是正则表达式。
010101101*
(11|0*)* 都是正则表达式。
|S|<=100。


区间DP判断正则表达式是否合法
对于1:枚举字符串每一个字符,if(s[i]=='0'||s[i]=='1') dp[i][i]=1;else dp[i][i]=0;

2:枚举断点,if(dp[i][k]&&dp[k+1][r]) dp[l][r]=1;

3:if(s[l]==‘(’&&s[r]==')'&&dp[l+1][r-1]) dp[l][r]=1;

4:if(s[r]=='*'&&dp[l][r-1]) dp[l][r]=1;

5:枚举'|'的位置 if(s[k]=='|'&&dp[l][k]&&dp[k+1][r]) dp[l][r]=1;

最终if(dp[1][n]) cout<<yes ;else cout<<no;

    

猜你喜欢

转载自www.cnblogs.com/Loi-Brilliant/p/8987746.html