区间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 }
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 }
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 }
https://acm.sdut.edu.cn/onlinejudge3/problems/1309
以上是关于区间dp的主要内容,如果未能解决你的问题,请参考以下文章