区间dp

Posted showend

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了区间dp相关的知识,希望对你有一定的参考价值。

https://zoj.pintia.cn/problem-sets/91827364500/problems/91827368971

需要判断凸包,学了再来补;

先说dp部分,

dp[ i ][ j ]表示划分起点为i,终点为j的凸多边形所需的花费;

dp [ i ] [ j ] =min ( dp[ i ][ j ] , dp[ i ] [ k ]+dp [ k ] [ j ] + cost [ i ] [ k ] +cost [ k ] [ j ] ) 

 

 

 

http://poj.org/problem?id=2955

括号匹配,经典区间dp;

分两种情况;

如果 ch[i] 与 ch【j】匹配,dp【i】【j】=max (dp[ i ]【j】,dp【i+1】【j-1】+2)

如果不匹配;

则按照区间dp模板;

注意,枚举k得时候第一种情况也要计算一遍;

技术图片
 1 #include<string.h>
 2 #include<iostream>
 3 #include<cstdio>
 4 using namespace std;
 5 const int maxn=110;
 6 char ch[maxn];
 7 int dp[300][300];
 8 int main()
 9 {
10     while(scanf("%s",ch)!=EOF)
11     {
12         if(ch[0]==e) break;
13         int t=strlen(ch);
14         for(int len=2;len<=t;len++)
15         {
16             for(int i=0;i+len-1<t;i++)
17             {
18                 int j=i+len-1;                    
19                 if((ch[i]==(&&ch[j]==))||(ch[i]==[&&ch[j]==])) dp[i][j]=max(dp[i][j],dp[i+1][j-1]+2);
20                 for(int k=i;k<j;k++)
21                 {
22                     dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]);
23                 }
24             }
25         }
26         cout<<dp[0][t-1]<<endl;
27         memset(dp,0,sizeof(dp));
28         memset(ch,0,sizeof(ch));
29     }
30     return 0;
31 }
View Code

 

http://poj.org/problem?id=1651

区间dp;

我的理解是:dp[ i ] [ k ] + dp[ k ] [ j ] +cost最后剩的元素只会左边和右边以及中间这个k,从i到k的最小值,加上从k-j的最小值,再加上去掉k所花的值;

技术图片
 1 #include<string.h>
 2 #include<iostream>
 3 #include<cstdio>
 4 using namespace std;
 5 const int inf=0x3f;
 6 const int maxn=110;
 7 int ch[maxn];
 8 int dp[300][300];
 9 int main()
10 {
11     int n;
12     cin>>n;
13     memset(dp,inf,sizeof(dp));
14     for(int i=1;i<=n;i++) cin>>ch[i],dp[i][i]=0,dp[i][i+1]=0;
15     for(int len=3;len<=n;len++)
16     {
17         for(int i=1;i+len-1<=n;i++)
18         {
19             int j=len+i-1;
20             for(int k=i;k<j;k++)
21             {
22                 dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]+ch[i]*ch[k]*ch[j]);//对于当k被抽出时,左边界为i,右边界为j的方案数值。
23             }
24         }
25     }
26     cout<<dp[1][n]<<endl;
27     return 0;
28 }
View Code

 

https://codeforces.com/problemset/problem/149/D

借鉴微博:https://blog.csdn.net/m0_38083668/article/details/82793071

有空多做几遍,刚开始读错题了;输入的括号序列已知是合法的。

括号序列合法,初始化时记录每个左括号所对应的右括号;

对于区间i,j。如果i与j配对则dp[ i ] [ j ] [x ][ y] +=dp[ i + 1 ] [ j - 1 ] [  ] [  ];//类似于括号配对问题

对于区间i ,j,端点i , j此次情况的方法数=dp[ i + 1 ] [ j - 1 ] [  ] [  ]的所有情况的和;加法原理;

如果不配对:那么找到i对应合法括号位置tag,则dp[ i ] [ j ]...+=dp[ i ][ tag] [ ] [ ] *dp[ tag+1 ][ j ] [ ] [  ]; 

技术图片
 1 #include<string.h>
 2 #include<iostream>
 3 #include<cstdio>
 4 using namespace std;
 5 #define int long long
 6 const int mo=1e9+7;
 7 char ch[800];
 8 int dp[710][710][3][3],p[800];//0代表不涂色,1代表涂红,2代表蓝
 9 void dfs(int l,int r)
10 {
11     if(l==(r-1))
12     {
13         dp[l][r][1][0]=1;
14         dp[l][r][0][1]=1;
15         dp[l][r][0][2]=1;
16         dp[l][r][2][0]=1;
17         return;
18     }
19     if(p[l]==r)
20     {
21         dfs(l+1,r-1);
22         for(int i=0;i<=2;i++)
23         for(int j=0;j<=2;j++){
24         if(j!=1) dp[l][r][0][1]=(dp[l][r][0][1]+dp[l+1][r-1][i][j])%mo;
25         if(i!=1) dp[l][r][1][0]=(dp[l][r][1][0]+dp[l+1][r-1][i][j])%mo;
26         if(j!=2) dp[l][r][0][2]=(dp[l][r][0][2]+dp[l+1][r-1][i][j])%mo;
27         if(i!=2) dp[l][r][2][0]=(dp[l][r][2][0]+dp[l+1][r-1][i][j])%mo;
28         }
29     }
30     else{
31         dfs(l,p[l]);
32         dfs(p[l]+1,r);//不配对;
33         for(int i=0;i<=2;i++)
34         {
35             for(int j=0;j<=2;j++)
36             {
37                 for(int k=0;k<=2;k++){
38                     for(int h=0;h<=2;h++){
39                     if(k==h&&h&&k) continue;
40                     dp[l][r][i][j]=(dp[l][r][i][j]+dp[l][p[l]][i][k]*dp[p[l]+1][r][h][j]%mo)%mo;
41                     }
42                 }
43             }
44         }
45     }
46 }
47 signed main()
48 {
49     scanf("%s",ch+1);
50     int t=0;
51     t=strlen(ch+1);
52     for(int i=1;i<t;i++)
53     {
54        if(ch[i]==)) continue;
55         int cnt=0;
56         for(int j=i+1;j<=t;j++)
57         {
58             if(ch[j]==() cnt++;
59             else cnt--;
60             if(cnt==-1) {p[i]=j,p[j]=i;break;}
61         }
62     }
63     dfs(1,t);
64     int ans=0;
65     for(int i=0;i<=2;i++)
66     {
67         for(int j=0;j<=2;j++)
68         {
69             ans=(ans+dp[1][t][i][j])%mo;
70         }
71     }
72     cout<<ans<<endl;
73 }
View Code

 

https://acm.sdut.edu.cn/onlinejudge3/problems/1309

以上是关于区间dp的主要内容,如果未能解决你的问题,请参考以下文章

HDU 5115 Dire Wolf ——(区间DP)

HDU 5115 Dire Wolf(区间dp)

区间DP小结(附经典例题) 转载

poj2955 区间dp

BZOJ1260 [CQOI2007]涂色paint(区间dp)

括号匹配问题(区间dp)