HDU4632 Poj2955 括号匹配(一) 整数划分(四) 区间DP总结

  题意:给定一个字符串 输出回文子序列的个数    一个字符也算一个回文

很明显的区间dp  就是要往区间小的压缩!

#include<bits/stdc++.h>
using namespace std;
//input
#define rep(i,x,y) for(int i=(x);i<=(y);++i)
#define RI(n) scanf("%d",&(n))
#define RII(n,m) scanf("%d%d",&n,&m);
#define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k)
#define RS(s) scanf("%s",s)
#define LL long long
#define REP(i,N)  for(int i=0;i<(N);i++)
#define CLR(A,v)  memset(A,v,sizeof A)
//////////////////////////////////
#define N 1005
#define inf 0x3f3f3f3f
#define mod 10007
int dp[N][N];

int main()
{
    int cas;
    cin>>cas;
    char s[1005];
    int kase=0;
    while(cas--)
    {
        CLR(dp,0);
        RS(s+1);
        int n=strlen(s+1);
        rep(i,1,n)
        dp[i][i]=1;//长度为一的区间肯定是一个回文
        
       rep(i,2,n)
       for(int j=i-1;j>=1;j--)//这样保证了 len从小到大!
       {
             dp[j][i]=(dp[j+1][i]+dp[j][i-1]-dp[j+1][i-1]+mod)%mod;//容斥原理  反正就是要将dp往区间短的转移
           if(s[i]==s[j])
              dp[j][i] = (dp[j][i]+dp[j+1][i-1]+1+mod)%mod;//如果两边相等  那么这两个数可与i+1 到j-1里所有回文序列组成一个回文序列 且它们自己也是一个回文序列所以要加一
       }
      printf("Case %d: %d\n",++kase,dp[1][n]);
    }
}
View Code

Poj2955 括号匹配(一)

给出一个的只有'(',')','[',']'四种括号组成的字符串,求 最多 有多少个括号满足题目里所描述的完全匹配。

状态转移方程:dp[i][j]表示第i~j个字符间的最大匹配字符数。

if(s[i] 与 s[j]匹配) dp[i][j] = d[[i+1][j-1] +2;

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

#include<bits/stdc++.h>
using namespace std;
//input
#define rep(i,x,y) for(int i=(x);i<=(y);++i)
#define RI(n) scanf("%d",&(n))
#define RII(n,m) scanf("%d%d",&n,&m);
#define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k)
#define RS(s) scanf("%s",s)
#define LL long long
#define REP(i,N)  for(int i=0;i<(N);i++)
#define CLR(A,v)  memset(A,v,sizeof A)
//////////////////////////////////
#define N 1005
#define inf 0x3f3f3f3f
#define mod 10007
int dp[N][N];

int main()
{
  char s[N];
  while(RS(s+1)==1)
  {
      CLR(dp,0);
      int n=strlen(s+1);
      rep(i,1,n-1)
     // if(s[i]=='('&&s[i+1]==')'||s[i]=='['&&s[i+1]==']')
     //   dp[i][i+1]=1;
     rep(len,1,n)
     for(int i=1,j=i+len-1;j<=n;i++,j=i+len-1)
     {
          if((s[i]=='('&&s[j]==')')||(s[i]=='['&&s[j]==']'))
                dp[i][j] = dp[i+1][j-1]+2; //如果匹配,先更新
                
            for(int k = i;k<j;k++)//区间合并
            {//k<j
                dp[i][j] = max(dp[i][j],dp[i][k]+dp[k+1][j]);
            }
     }
   cout<<dp[1][n]<<endl;
  }
}

整数划分

给出一个数n,要求在n的数位间插入(m-1)个乘号,将n分成了m段,求这m段的最大乘积。

样例输入

2

111 2

1111 2

样例输出

11

121

状态转移方程为

dp[i][j]=max(dp[i][j],dp[k][j-1]*num[k+1][i])

其中num[i][j]表示从s[i]到s[j]这段连续区间代表的数值。

#include<bits/stdc++.h>
using namespace std;
//input
#define rep(i,x,y) for(int i=(x);i<=(y);++i)
#define RI(n) scanf("%d",&(n))
#define RII(n,m) scanf("%d%d",&n,&m);
#define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k)
#define RS(s) scanf("%s",s)
#define LL long long
#define REP(i,N)  for(int i=0;i<(N);i++)
#define CLR(A,v)  memset(A,v,sizeof A)
//////////////////////////////////
#define N 1005
#define inf 0x3f3f3f3f
#define mod 10007
int dp[N][N];
int num[ N][N];
int main()
{
   char s[1000];
   int n,m;
   RS(s+1);
   RI(m);
   n=strlen(s+1);
   rep(i,1,n)
   {
       num[i][i]=s[i]-'0';
       rep(j,i+1,n)
       num[i][j]=num[i][j-1]*10+s[j]-'0';
   }
   rep(i,1,n)
   dp[i][0]=num[1][i];

   rep(j,1,m-1)//乘号一个个放入 因为每次dp[i][j] 由dp[i][j-1]转移而来  所以要j从小到大开始枚举  就像之前的要len从小到大开始枚举 因为每一个长区间取决于短区间
   rep(i,j+1,n)
   rep(k,j,i-1)
   dp[i][j]=max(dp[i][j],dp[k][j-1]*num[k+1][i] );
  cout<<dp[n][m-1];
}
View Code

猜你喜欢

转载自www.cnblogs.com/bxd123/p/10513541.html
今日推荐