区间DP问题(矩阵连乘,石子合并,括号匹配)

矩阵连乘源码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <cstring>
#include <climits>
#include <cmath>
#include <cctype>

typedef long long ll;
using namespace std;

int m[110][110];
int a[110];
int n;

int course(int i,int j)
{
    if(m[i][j] != -1)//已经算出来这个值,直接返回
    {
        return m[i][j];
    }
    if(i == j)
    {
        return 0;
    }
    if(i == j-1)
    {
        m[i][j] = a[i] * a[i+1] * a[i+2];
        return m[i][j];
    }
    int u = course(i,i) + course(i+1,j) + a[i] * a[i+1] * a[j+1];
    int k,t;
    for(k=i+1; k<j; k++)
    {
        t = course(i,k) + course(k+1,j) + a[i] * a[k+1] * a[j+1];
        if(t < u)
            u = t;
    }
    m[i][j] = u;
    return m[i][j];
}

int main()
{
    int i;
    while(scanf("%d",&n) != EOF)
    {
        memset(m,-1,sizeof(m));//设置备忘录。刚开始初始值为-1
        for(i=1; i<=n+1; i++)
        {
            scanf("%d",&a[i]);
        }
        int sum = course(1,n);
        printf("%d\n",sum);
    }
    return 0;
}

题目地址:http://acm.nyist.net/JudgeOnline/problem.php?pid=536

思路:在模板上的简单改动

AC代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <cstring>
#include <climits>
#include <cmath>
#include <cctype>

typedef long long ll;
using namespace std;

int m[110][110];
int a[110];
int n;

int course(int i,int j)
{
    if(m[i][j] != -1)//已经算出来这个值,直接返回
    {
        return m[i][j];
    }
    if(i == j)
    {
        return 0;
    }
    if(i == j-1)
    {
        m[i][j] = a[i] * a[i+1] * a[i+2];
        return m[i][j];
    }
    int u = course(i,i) + course(i+1,j) + a[i] * a[i+1] * a[j+1];
    int k,t;
    for(k=i+1; k<j; k++)
    {
        t = course(i,k) + course(k+1,j) + a[i] * a[k+1] * a[j+1];
        if(t < u)
            u = t;
    }
    m[i][j] = u;
    return m[i][j];
}

int main()
{
    int i;
    while(scanf("%d",&n) != EOF)
    {
        int b;
        memset(m,-1,sizeof(m));//设置备忘录。刚开始初始值为-1
        for(i=1; i<=n-1; i++)
        {
            scanf("%d%d",&a[i],&b);
        }
        scanf("%d%d",&a[n],&a[n+1]);
        int sum = course(1,n);
        printf("%d\n",sum);
    }
    return 0;
}

石子合并

题目地址:http://acm.nyist.net/JudgeOnline/problem.php?pid=737

思路:区间DP问题(矩阵连乘,石子合并,括号匹配)_第1张图片

从最中间的一条线向右上角斜着算,和矩阵连乘类似,可以用四边形不等式优化

四边形不等式详解地址:http://blog.163.com/dqx_wl/blog/static/2396821452015111133052112/

AC代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <cstring>
#include <climits>
#include <cmath>
#include <cctype>

typedef long long ll;
using namespace std;

int a[210];
int dp[210][210];
int s[210][210];

int main()
{
    int n,i,j,k,r;
    while(scanf("%d",&n) != EOF)
    {
        for(i=1; i<=n; i++)
        {
            scanf("%d",&a[i]);
        }
        for(i=1; i<=n; i++)
        {
            s[i][i] = a[i];
            for(j=i+1; j<=n; j++)
            {
                s[i][j] = s[i][j-1] + a[j];//得出合并区间i到j的结果
            }
        }
        for(r=2; r<=n; r++)
        {
            for(i=1; i<=n-r+1; i++)
            {
                j = i + r - 1;
                dp[i][j] = INT_MAX;
                for(k=i; k<j; k++)
                {
                    if(dp[i][j] > dp[i][k] + dp[k+1][j])
                    {
                        dp[i][j] = dp[i][k] + dp[k+1][j];
                    }
                }
                dp[i][j] += s[i][j];
            }
        }
        printf("%d\n",dp[1][n]);
    }
    return 0;
}

题目地址:点击打开链接

思路:注意数组是从a+1开始存的

AC代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <cstring>
#include <climits>
#include <cmath>
#include <cctype>

typedef long long ll;
using namespace std;

char a[110];
int dp[110][110];

int main()
{
    int i,j,k,l;
    while(scanf("%s",a+1))
    {
        memset(dp,0,sizeof(dp));
        if(!strcmp(a+1,"end"))
            break;
        int len = strlen(a+1);
        for(l=2; l<=len; l++)
        {
            for(i=1; i<=len-l+1; i++)
            {
                j = i + l - 1;
                if((a[i] == '(' && a[j] == ')') || ( a[i] == '[' && a[j] == ']'))
                {
                    dp[i][j] = dp[i+1][j-1] + 2;
                }
                for(k=i; k<j; k++)
                {
                    dp[i][j] = max(dp[i][j],dp[i][k] + dp[k+1][j]);
                }
            }
        }
        printf("%d\n",dp[1][len]);
    }
    return 0;
}




你可能感兴趣的:(区间DP问题(矩阵连乘,石子合并,括号匹配))