寒假训练DP

一.区间DP

D - Palindrome
Time Limit:3000MS    Memory Limit:65536KB    64bit IO Format:%I64d & %I64u

Description

A palindrome is a symmetrical string, that is, a string read identically from left to right as well as from right to left. You are to write a program which, given a string, determines the minimal number of characters to be inserted into the string in order to obtain a palindrome.

As an example, by inserting 2 characters, the string "Ab3bd" can be transformed into a palindrome ("dAb3bAd" or "Adb3bdA"). However, inserting fewer than 2 characters does not produce a palindrome.

Input

Your program is to read from standard input. The first line contains one integer: the length of the input string N, 3 <= N <= 5000. The second line contains one string with length N. The string is formed from uppercase letters from 'A' to 'Z', lowercase letters from 'a' to 'z' and digits from '0' to '9'. Uppercase and lowercase letters are to be considered distinct.

Output

Your program is to write to standard output. The first line contains one integer, which is the desired minimal number.

Sample Input

5
Ab3bd

Sample Output

2

题意:  题目给出一个字符串和它的长度.求添加最小的字符数,使这个字符串成为回文串;

题解: 区间DP, dp[l,r]表示下标l到下标r这部分区间的最优解,则if(s[l] == s[r]) dp[l][r] = dp[l + 1][r- 1]; else dp[l][r] = min(dp[l][r - 1] + 1,dp[l + 1][r] + 1);

          这道题要注意要用滚动数组做,因为5000 * 5000 内存爆了;

AC代码:

<span style="font-size:12px;"><span style="font-size:12px;">#include <cstring>
#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <cctype>
#define INF 1e5 + 100

using namespace std;
typedef long long ll;
const int M = 5500;
int dp[2][M],n;
char s[M];


int main()
{
    scanf("%d %s",&n,s + 1);
    for(int i = n; i >= 1; i--)
    {
        for(int j = i; j <= n; j++)
        {
            if(i == j) dp[i % 2][j] = 0;
            else
            {
                if(s[i] == s[j])
                {
                    if(i + 1 == j) dp[i % 2][j] = 0;
                    else
                    dp[i % 2][j] = dp[(i + 1) % 2][j - 1];
                }
                else dp[i % 2][j] = min(dp[i % 2][j - 1] + 1,dp[(i + 1) % 2][j] + 1);
            }
        }
    }
    printf("%d\n",dp[1][n]);
    return 0;
}

Sample Output

6
6
4
0
6

题意: 题目给出一个字符串,求串中存在的最长的匹配串;

题解: (区间DP) 逆向考虑,先求出添加最少的字符使其为匹配串,然后用串的长度去减即可;

AC代码:
<span style="font-size:12px;">#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;
const int M = 110;
char s[M];
int dp[M][M];

bool check(int i,int j)
{
    if(s[i] == '(' && s[j] == ')') return true;
    if(s[i] == '[' && s[j] == ']') return true;
    return false;
}

int main()
{
    //freopen("in","r",stdin);
    while(~scanf("%s",s + 1))
    {
        int n;
        if(!strcmp(s + 1,"end")) break;
        n = strlen(s + 1);
        memset(dp,0,sizeof(dp));
        for(int i = n; i >= 1; i--)
        {
            dp[i][i] = 1;
            for(int j = i + 1; j <= n; j++)
            {
                if(check(i,j))
                {
                    if(i + 1 == j) dp[i][j] = 0;
                    else dp[i][j] = dp[i + 1][j - 1];
                }
                else dp[i][j] = min(dp[i + 1][j] + 1,dp[i][j - 1] + 1);
                for(int k = i + 1; k < j - 1; k++)
                    dp[i][j] = min(dp[i][j],dp[i][k] + dp[k + 1][j]);
            }
        }
        printf("%d\n",n - dp[1][n]);
    }
    return 0;
}
</span>

C - Brackets Sequence

Time Limit:1000MS    Memory Limit:65536KB    64bit IO Format:%I64d & %I64u

Description

Let us define a regular brackets sequence in the following way:

1. Empty sequence is a regular sequence.
2. If S is a regular sequence, then (S) and [S] are both regular sequences.
3. If A and B are regular sequences, then AB is a regular sequence.

For example, all of the following sequences of characters are regular brackets sequences:

(), [], (()), ([]), ()[], ()[()]

And all of the following character sequences are not:

(, [, ), )(, ([)], ([(]

Some sequence of characters '(', ')', '[', and ']' is given. You are to find the shortest possible regular brackets sequence, that contains the given character sequence as a subsequence. Here, a string a1 a2 ... an is called a subsequence of the string b1 b2 ... bm, if there exist such indices 1 = i1 < i2 < ... < in = m, that aj = bij for all 1 = j = n.

Input

The input file contains at most 100 brackets (characters '(', ')', '[' and ']') that are situated on a single line without any other characters among them.

Output

Write to the output file a single line that contains some regular brackets sequence that has the minimal possible length and contains the given sequence as a subsequence.

Sample Input

([(]

Sample Output

()[()]

题意: 括号匹配问题,跟上面的一样,不过需要输出最优解的路径.

题解:区间DP,以dp[i][j]表示i到j这段区间的最优解,然后找出状态. 最后输出路径时只需递归输出,不过这道题目需要注意空串的情况.

AC代码:
#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;
const int M = 110;
char s[M],t[M];
int dp[M][M];

bool check(int i,int j)
{
    if(s[i] == '(' && s[j] == ')') return true;
    if(s[i] == '[' && s[j] == ']') return true;
    return false;
}

void unit(int x)
{
    switch(s[x])
    {
    case '(':
        t[x] = ')';
        break;
    case ')':
        t[x] = '(';
        break;
    case '[':
        t[x] = ']';
        break;
    case ']':
        t[x] = '[';
        break;
    }
}

void dfs(int i,int j)
{
    if(i > j) return ;
    if(check(i,j))
    {
        if(dp[i][j] == dp[i + 1][j - 1])
            dfs(i + 1,j - 1);
        else
        {
            for(int k = i + 1; k < j - 1; k++)
            {
                if(dp[i][j] == dp[i][k] + dp[k + 1][j])
                {
                    dfs(i,k);
                    dfs(k + 1,j);
                    break;
                }
            }
        }
    }
    else
    {
        if(dp[i][j] == dp[i][j - 1] + 1)
        {
            unit(j);
            dfs(i,j - 1);
        }
        else if(dp[i][j] == dp[i + 1][j] + 1)
        {
            unit(i);
            dfs(i + 1,j);
        }
        else
        {
            for(int k = i + 1; k < j - 1; k++)
            {
                if(dp[i][j] == dp[i][k] + dp[k + 1][j])
                {
                    dfs(i,k);
                    dfs(k + 1,j);
                    break;
                }
            }
        }
    }
}

int main()
{
    //freopen("in","r",stdin);
    scanf("%s",s + 1);
    int n;
    n = strlen(s + 1);
    memset(dp,0,sizeof(dp));
    memset(t,0,sizeof(t));
    for(int i = n; i >= 1; i--)
    {
        dp[i][i] = 1;
        for(int j = i + 1; j <= n; j++)
        {
            if(check(i,j))
            {
                if(i + 1 == j) dp[i][j] = 0;
                else dp[i][j] = dp[i + 1][j - 1];
            }
            else dp[i][j] = min(dp[i + 1][j] + 1,dp[i][j - 1] + 1);
            for(int k = i + 1; k < j - 1; k++)
                dp[i][j] = min(dp[i][j],dp[i][k] + dp[k + 1][j]);
        }
    }
    //printf("%d\n",dp[1][n]);
    if(dp[1][n]) dfs(1,n);
    for(int i = 1; i <= n; i++)
    {
        if(t[i])
        {
            if(s[i] == ')' || s[i] == ']') printf("%c%c",t[i],s[i]);
            else printf("%c%c",s[i],t[i]);
        }
        else printf("%c",s[i]);
    }
    puts("");
    return 0;
}
//([]][])

E - To the Max

Time Limit:1000MS    Memory Limit:10000KB    64bit IO Format:%I64d & %I64u

Description

Given a two-dimensional array of positive and negative integers, a sub-rectangle is any contiguous sub-array of size 1*1 or greater located within the whole array. The sum of a rectangle is the sum of all the elements in that rectangle. In this problem the sub-rectangle with the largest sum is referred to as the maximal sub-rectangle.
As an example, the maximal sub-rectangle of the array:

0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2
is in the lower left corner:

9 2
-4 1
-1 8
and has a sum of 15.

Input

The input consists of an N * N array of integers. The input begins with a single positive integer N on a line by itself, indicating the size of the square two-dimensional array. This is followed by N^2 integers separated by whitespace (spaces and newlines). These are the N^2 integers of the array, presented in row-major order. That is, all numbers in the first row, left to right, then all numbers in the second row, left to right, etc. N may be as large as 100. The numbers in the array will be in the range [-127,127].

Output

Output the sum of the maximal sub-rectangle.

Sample Input

4
0 -2 -7 0 9 2 -6 2
-4 1 -4  1 -1

8  0 -2

Sample Output

15
题意: 给你一个矩阵,叫你找出一个最大子矩阵;

题解:暴力枚举,DP(dp(i,j)表示最大子矩阵的行数在i到j,之间,然后枚举列数就好了);

AC代码:

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;
const int M = 110;
const int INF = -1e9;
int dp[M][M],sum[M][M];

int main()
{
    int n,res = INF;
    cin>>n;
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= n; j++)
        {
            int x;
            scanf("%d",&x);
            sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + x;
        }
    for(int i = 1; i <= n; i++)
    {
        for(int j = i; j <= n; j++)
        {
            int ans = INF;
            for(int k = 1; k <= n; k++)
            {
                for(int p = k; p <= n; p++)
                {
                    ans = max(ans,sum[j][p] - sum[i - 1][p] - sum[j][k - 1] + sum[i - 1][k - 1]);
                }
            }
            res = max(ans,res);
        }
    }*
    printf("%d\n",res);
    return 0;
}

/**********************************************/

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;
const int M = 110;
const int INF = -1e9;
int dp[M][M],sum[M][M];

int main()
{
    int n;
    cin>>n;
    memset(sum,0,sizeof(sum));
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= n; j++)
        {
            int x;
            scanf("%d",&x);
            sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + x;
            dp[i][j] = sum[i][j];
            for(int k = 1; k < i; k++)
                dp[i][j] = max(dp[i][j],max(dp[k][j],sum[i][j] - sum[k][j]));
            for(int k = 1; k < j; k++)
                dp[i][j] = max(dp[i][j],max(dp[i][k],sum[i][j] - sum[i][k]));
            for(int k = 1; k < i; k++)
            {
                for(int p = 1; p < j; p++)
                {
                    dp[i][j] = max(dp[i][j],sum[i][j] - sum[k][j] - sum[i][p] + sum[k][p]);
                }
            }
        }
    }
    printf("%d\n",dp[n][n]);
    return 0;
}





你可能感兴趣的:(dp)