UVa11404Palindromic Subsequence(最大回文串,区间DP)

Description

A Subsequence is a sequence obtained by deleting zero or more characters in a string. A Palindrome is a string which when read from left to right, reads same as when read from right to left. Given a string, find the longest palindromic
subsequence. If there are many answers to it, print the one that comes lexicographically earliest.

Constraints

  • Maximum length of string is 1000.
  • Each string has characters `a‘ to `z‘ only.

Input

Input consists of several strings, each in a separate line. Input is terminated by EOF.

Output

For each line in the input, print the output in a single line.

Sample Input

aabbaabb
computer
abzla
samhita

Sample Output

aabbaa
c
aba
aha

题意:

给定一个字符串s,对s进行删除操作,使得剩下的子串是回文字符串,输出最长的字符串,当有多个相同长度的就输出字典序最小的。

思路:

由于要输出字符串,所以在状态转移过程中要保存下字符串,用C++的string就方便很多,然后就是和找最长回文的方法一样了。

定义结构体保存长度,以及字符串,分别用len, s 表示

状态的转移方程为,如果头尾相同,dp[i][j].len = dp[i + 1][j - 1].len + 2(长度加上首尾,所以增加2);如果首尾不同,那么回文长度不增加 dp[i][j].len = max(dp[i + 1][j].len, dp[i][j - 1].len);

如果长度相同  dp[i + 1][j].len, == dp[i][j - 1].len,那么就要比较子串的字典序,取字典序小的,

也就是判断 dp[i + 1][j].s,  dp[i][j - 1].s。

<span style="font-size:18px;">#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <string>
#include <algorithm>
#include <queue>
#include <stack>
using namespace std;

const double PI = acos(-1.0);
const double e = 2.718281828459;
const double eps = 1e-8;
const int MAXN  = 1010;
struct str
{
    int len;
    string s;
} dp[MAXN][MAXN];
char s[MAXN];

int main()
{
    //freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);
    while(scanf("%s", s+1) != EOF)
    {
        int len = strlen(s+1);
        for(int i = 1; i <= len; i++)
        {   //初始化
            dp[i][i].len = 1;
            dp[i][i].s = s[i];
        }
        for(int k = 2; k <= len; k++) //控制区间大小
        {
            for(int i = 1, j = k; j <= len; i++, j++) //正推
            //for(int i = len-k+1, j = len; i >= 1; i--, j--) //逆推
            {
                if(s[i] == s[j])
                {
                    dp[i][j].len = dp[i+1][j-1].len+2;
                    dp[i][j].s = s[i]+dp[i+1][j-1].s+s[j];
                }
                else
                {
                    if(dp[i][j-1].len > dp[i+1][j].len ||
                            (dp[i][j-1].len==dp[i+1][j].len&&dp[i][j-1].s<dp[i+1][j].s))
                    {   //当 [i, j-1] 的长度大于 [i+1, j] 的长度,或者二者长度相等并且
                        //[i, j-1] 的字典序小于 [i+1, j] 的字典序,则选择 [i, j-1],否则选择后者
                        dp[i][j].len = dp[i][j-1].len;
                        dp[i][j].s = dp[i][j-1].s;
                    }
                    else
                    {
                        dp[i][j].len = dp[i+1][j].len;
                        dp[i][j].s = dp[i+1][j].s;
                    }
                }
            }
        }
        cout<<dp[1][len].s<<endl;
    }
    return 0;
}
</span>

时间: 2024-10-08 09:44:56

UVa11404Palindromic Subsequence(最大回文串,区间DP)的相关文章

回文串区间dp

UVa 10739 String to Palindrome(经典回文串区间DP) 题意: 给定一个字符串,可以对其进行删除,插入,替换操作. 问最少经过几次操作,可以使这个字符串变成回文字符串. 思路: 看得别人的 题解,最优化问题,用较为直接的方法处理时发现情况很复杂,很多时候就要考虑动态规划了.先从整体出发,由大到小,看往少一个两个元素的情况进行最优递归,如何得到结果. (这里区间DP即是不断向两侧扩大规模) (1)如果最外层两个字符相同,s[0]==s[n],那么这两个字符外侧肯定不用考

UVa 10617 Again Palindrome(回文串区间DP)

UVa 10617 Again Palindrome(经典回文串区间DP) 题意: 给定一个字符串s,对s进行删除操作,使得剩下的子串是回文字符串,问最多有多少种这种子串. 思路: 涉及到回文字符串,首先要想到的肯定是区间DP,如何写出状态转移方程? 直接从题意切入:dp[i, j]表示区间[i, j]最多有多少个这样的子串. 1. s[i] == s[j] 去掉s[i],则一个子问题就是dp[i+1, j]; 去掉s[j],另一个子问题就是dp[i, j-1]; 显然这两个子问题是会有重叠的,

关于回文串的DP问题

问题1:插入/删除字符使得原字符串变成一个回文串且代价最小 poj 3280 Cheapest Palindrome 题意:给出一个由m中字母组成的长度为n的串,给出m种字母添加和删除花费的代价,求让给出的串变成回文串的代价. Sol: 插入和删除等价,因此只需要保留 min(插入代价,删除代价)作为调整字符串的代价 如果 s[i]==s[j],那么将区间(i,j)变为回文串的代价和将区间(i+1,j-1)变为回文串的代价相同,因为此时不需要修改 如果不同,必然要将 s[i]和s[j]改为同一字

最长回文子序列 区间dp

J - 买票回家啦 Time Limit:1000MS    Memory Limit:65535KB    64bit IO Format: SubmitStatusPracticeNBUT 1586 Description 集训要结束了,同学们就准备回家了.好舍不得回家阿.(那就再待一个月嘛,就这么愉快地决定了.)超哥要回家了,可是他没有挤进12306官网, 可怜的他就随便找了个能代购车票的网站.结果,当他付钱时傻眼了,这个网站竟然要验证码.验证码嘛就照着样子输入就好了呀,哦不,这个网站管理

回文串 --- 动态dp UVA 11584

题目链接: https://cn.vjudge.net/problem/34398/origin 本题的大意其实很简单,就是找回文串,大致的思路如下: 1. 确定一个回文串,这里用到了自定义的check函数原理如下: 传入le, ri两个值(定义从1开始), s+1 = aaadbccb. a a a d b c c b 1 2 3 4 5 6 7 8 比如,le = 5, ri = 8. 则s[5] == s[8]成立 le++ ri-- 再比较 s[6] == s[7]? 成立 le++,

bzoj 1710: [Usaco2007 Open]Cheappal 廉价回文【区间dp】

只要发现添加一个字符和删除一个字符是等价的,就是挺裸的区间dp了 因为在当前位置加上一个字符x就相当于在他的对称位置删掉字符x,所以只要考虑删除即可,删除费用是添加和删除取min 设f[i][j]为从i到j的价格,长度从小到大枚举更新就行了 f[i][j]=min(f[i][j-1]+cost[s[j]],f[i+1][j]+cost[s[i]]),如果s[i]==s[j]还能和f[i+1][j-1]取个min cpp #include<iostream> #include<cstdio

HDU 4632 Palindrome subsequence(区间dp,回文串,字符处理)

题目 参考自博客:http://blog.csdn.net/u011498819/article/details/38356675 题意:查找这样的子回文字符串(未必连续,但是有从左向右的顺序)个数. 简单的区间dp,哎,以为很神奇的东西,其实也是dp,只是参数改为区间,没做过此类型的题,想不到用dp,以后就 知道了,若已经知道[0,i],推[0,i+1], 显然还要从i+1 处往回找,dp方程也简单: dp[j][i]=(dp[j+1][i]+dp[j][i-1]+10007-dp[j+1][

POJ 3280 Cheapest Palindrome(区间DP求改成回文串的最小花费)

题目链接:http://poj.org/problem?id=3280 题目大意:给你一个字符串,你可以删除或者增加任意字符,对应有相应的花费,让你通过这些操作使得字符串变为回文串,求最小花费.解题思路:比较简单的区间DP,令dp[i][j]表示使[i,j]回文的最小花费.则得到状态转移方程: dp[i][j]=min(dp[i][j],min(add[str[i]-'a'],del[str[i]-'a'])+dp[i+1][j]); dp[i][j]=min(dp[i][j],min(add[

LightOJ - 1205:Palindromic Numbers (数位DP&amp;回文串)

A palindromic number or numeral palindrome is a 'symmetrical' number like 16461 that remains the same when its digits are reversed. In this problem you will be given two integers i j, you have to find the number of palindromic numbers between i and j

NYOJ 1023 还是回文(DP,花最少费用形成回文串)

1 /* 2 题意:给出一串字符(全部是小写字母),添加或删除一个字符,都会产生一定的花费. 3 那么,将字符串变成回文串的最小花费是多少呢? 4 5 思路:如果一个字符串增加一个字符 x可以形成一个回文串,那么从这个字符串中删除这个字符 x 6 同样也能形成回文串! 7 所以我们只记录删除,和增加这个字符 x 的最小的费用就好了!->转变成添加多少个字符形成回文串费用最少! 8 9 str[i]!=str[k] 10 dp[i][j]=min(dp[i][j-1]+cost[str[k]-'a