ACM: 回文串 dp题 poj 1159  (滚动…

本文介绍了一种算法,用于确定将任意字符串转换为回文串所需的最少字符插入数量。通过动态规划方法,实现了高效的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

                                                          Palindrome

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

题意: 给你一个字符串,计算最少插入多少个字母形成回文串.

解题思路:

               1. dp题肯定先找出状态转移方程. 一开始想把串分成两部分找最长相同字串.

               2. 但是发现并不是同时两个字串都要添加字母,每次只是添加一个就行.

               3. 状态转移方程: 设dp[i][j]是第i到第j字符需要至少添加多少个字符形成回文串.

                    即: if(str[i] == str[j]) dp[i][j] = dp[i+1][j-1];   (i = n-1 >> i = 1;)  (j = i+1 >> j = n)

                         else dp[i][j] = min(dp[i+1][j] , dp[i][j-1]) + 1;

               4. 郁闷的是发现5000的二位数组开不下.T.T.网上看见讨论用.short型.还好暴力AC.

               5. 还发现大牛们的是滚动数组. 每次只需e = 1-e;变换即可. 学习学习.

代码1:

#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
#define MAX 5005

int n;
char str[MAX];
short dp[MAX][MAX];

inline int min(int a,int b)
{
    return a > b ? a : b;
}

int main()
{
//    freopen("input.txt","r",stdin);
    while(scanf("%d",&n) != EOF)
    {
        getchar();
        int i, j;
        for(i = n; i >= 1; --i)
            scanf("%c",&str[i]);
        str[i] = '\0';
        memset(dp,0,sizeof(dp));
        
        for(int i = n-1; i >= 1; --i)
        {
            for(int j = i+1; j <= n; ++j)
            {
                if(str[i] == str[j])
                    dp[i][j] = dp[i+1][j-1];
                else
                    dp[i][j] = min(dp[i+1][j],dp[i][j-1])+1;
            }
        }
        printf("%d\n",dp[1][n]);
    }
    return 0;
}


代码2:

#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
#define MAX 5005

int n;
char str1[MAX], str2[MAX];
int dp[2][MAX];

inline int max(int a,int b)
{
    return a > b ? a : b;
}

int main()
{
//    freopen("input.txt","r",stdin);
    while(scanf("%d",&n) != EOF)
    {
        getchar();
        for(int i = 1; i <= n; ++i)
            scanf("%c",&str1[i]);
        str1[n+1] = '\0';
        for(int i = 1; i <= n; ++i)
            str2[i] = str1[n-i+1];
        str2[n+1] = '\0';
       
        memset(dp,0,sizeof(dp));
        int e = 0;
        for(int i = 1; i <= n; ++i)
        {
            e = 1^e;
            for(int j = 1; j <= n; ++j)
            {
                if(str1[i] == str2[j])
                    dp[e][j] = dp[1^e][j-1] + 1;
                else
                    dp[e][j] = max(dp[e][j-1],dp[1^e][j]);
            }
        }
        printf("%d\n",n-dp[1^e][n]);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值