区间dp基础(石子归并,括号匹配,整数划分。。。)

来源:互联网 发布:js给select标签负值 编辑:程序博客网 时间:2024/04/30 20:37

区间dp基础

最近在做区间dp,感觉一开始走的有点远了,还是应该从经典的题型开始学习。
http://blog.csdn.net/y990041769/article/details/24194605 这微博主讲的很清楚了,我也就是记一些自己的想法。

1.石子归并

题目:http://acm.nyist.edu.cn/JudgeOnline/problem.php?pid=737
分析:感觉区间dp递推方法的套路就是,先枚举区间大小,再枚举起点,得到终点,然后枚举起终点中的中间点得到最优值,然后不同的题目还有一些小变化。dp [ i ] [ j ]为从第i个石子到第j个石子的合并最小代价。sum[i]就是1~i的石子的和用于辅助计算。

#include<iostream>#include<algorithm>#include<vector>#include<cstring>#include<queue>#include<map>#include<cstdio>#include<cstring>#define maxn 200#define INF 0xfffffffusing namespace std;int n;int sum[210],a[210];int dp[210][210];int main(){    while(scanf("%d",&n)!=EOF)    {        sum[0]=0;        for(int i=1; i<=n; i++)        {            scanf("%d",&a[i]);            sum[i]=sum[i-1]+a[i];        }        memset(dp,0,sizeof(dp));        for(int l=2; l<=n; l++)        {            for(int i=1; i+l-1<=n; i++)            {                int j=i+l-1;                dp[i][j]=INF;                for(int k=i; k<j; k++)                    dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]);            }        }        printf("%d\n",dp[1][n]);    }}

平行四边形优化:待看。。。。

2.括号匹配

题目:http://poj.org/problem?id=2955
分析:和之前石子归并差不多意思,就是因为“括号匹配”,所以对于匹配的起终点,有dp[i][j]=dp[i+1][j-1]+2;的初始化,之后还是枚举中间点找最优值。

#include<iostream>#include<algorithm>#include<vector>#include<cstring>#include<queue>#include<map>#include<cstdio>#include<cstring>#define maxn 200#define INF 0xfffffffusing namespace std;char s[110];int dp[110][110];int main(){    while(scanf("%s",s)!=EOF&&strcmp(s,"end"))    {        int n=strlen(s);        memset(dp,0,sizeof(dp));        for(int len=1; len<n; len++)        {            for(int i=0; i+len<n; i++)            {                int j=i+len;                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++)                    dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]);            }        }        printf("%d\n",dp[0][n-1]);    }}

打印路径:待看。。。

整数划分

题目:http://acm.nyist.net/JudgeOnline/problem.php?pid=746
分析:这道题就和原来的套路不一样了,定义dp [ i ] [ j ]为从开始到 i 中加入 j 个乘号得到的最大值。dp [ i ] [ j ] = max (dp [ i ] [ j ] , dp [ k ] [ j-1 ] * a [ k+1 ] [ i ] ) ;a[i][j]表示i~j的数字的数值。

#include<iostream>#include<algorithm>#include<vector>#include<cstring>#include<queue>#include<map>#include<cstdio>#include<cstring>#define maxn 200#define INF 0xfffffffusing namespace std;long long  a[25][25];char n[25];int m;long long dp[25][25];int main(){    int T;    scanf("%d",&T);    while(T--)    {        scanf("%s",n+1);        scanf("%d",&m);        int l=strlen(n+1);        memset(a,0,sizeof(a));        memset(dp,0,sizeof(dp));        for(int i=1; i<=l; i++)        {            a[i][i]=n[i]-'0';            for(int j=i+1; j<=l; j++)            {                a[i][j]=a[i][j-1]*10+(n[j]-'0');            }        }        for(int i=1; i<=l; i++) dp[i][1]=a[1][i];        for(int j=2; j<=m; j++)            for(int i=j; i<=l; i++)            {                for(int k=1; k<=i-1; k++)                {                    dp[i][j]=max(dp[i][j],dp[k][j-1]*a[k+1][i]);                }            }        printf("%lld\n",dp[l][m]);    }    return 0;}
0 0
原创粉丝点击