首页 > 其他分享 >POJ 1159 Palindrome

POJ 1159 Palindrome

时间:2022-12-24 10:55:35浏览次数:49  
标签:Palindrome 1159 5000 int scanf short POJ 字符串 dp

POJ 1159 Palindrome

题意:

给出一个字符串,求最少插入多少个字符可以让该字符串变成回文字符串

思路1:

思路1是卡过去的 (用 \(short\) 换 \(int\) 和用了一个常数优化),所以建议如果只看一种思路的话,移步思路2。

目的是使得整个字符串变成回文字符串,所以定义 \(f[i][j]\) 为将字符串 \(i-j\) 变成回文串需要插入的最少字符串。

注意这里有一个常数优化剪枝,就是当 \(s[i] == s[j]\) 时,可以直接返回 \(f[i + 1][j - 1]\) ,因为 从 \(f[i][j]\) 到 \(f[i +1][j-1]\) 一共就只有两种方法

  • \(f[i][j]->f[i+1][j] + 1->f[i + 1][j - 1] + 1 ->f[i + 1][j - 1]\)
  • \(f[i][j] ->f[i + 1][j - 1]\)

显然第二种肯定优于第一种,所以可以直接剪枝。

思路2:

倒着再把数组存一遍,找到两个字符串的 最长公共子序列 (LCS),字符串的长度减去 LCS 的长度就是结果。

最长公共子序列的转移方程为:

\(f[i][j] = max(f[i - 1][j],f[i][j - 1])\)

如果 \(a[i] == a[j]\) ,\(f[i][j] = max(f[i][j],f[i - 1][j - 1] + 1)\)

所以可以发现,这里直接使用滚动数组,就可以解决掉上面改用 \(short\) 来避免 \(MLE\) 的问题。

问题:

  • 没有注意空间大小,MLE 了, \(5000 * 5000 * 4 (int\; 4byte) / 1024 = 97,656.25KB\) 显然,超过的题目的限制 655536KB,然后观察了一下数据量,发现用 short 类型就可以了 \(5000 * 5000 * 2 (short\; 2byte) / 1024 = 48,828.125KB\)

实现:

//思路1
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 5e3 + 5, INF = 5003;
char s[N];
short f[N][N];

short dp(int i, int j)
{
    if (i >= j)
        return 0;
    if (f[i][j] != INF)
        return f[i][j];

    //f[i][j]->f[i+1][j] + 1->f[i + 1][j - 1] + 1 ->f[i + 1][j - 1]
    //f[i][j] ->f[i + 1][j - 1];
    //上面肯定不如下面优,所以直接剪枝
    if (s[i] == s[j])
    {
        return f[i][j] = min(f[i][j], short(dp(i + 1, j - 1)));
    }

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

    return f[i][j];
}

int main()
{
    int n;
    scanf("%d", &n);
    scanf("%s", s + 1);
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            f[i][j] = INF;

    printf("%d\n", dp(1, n));
    return 0;
}

//思路2
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 5e3 + 5;
char a[N], b[N];
int f[2][N];
int main()
{
    int n;
    scanf("%d", &n);
    scanf("%s", a + 1);
    for (int i = 1; i <= n; i++)
        b[n - i + 1] = a[i];

    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            f[i & 1][j] = max(f[(i & 1) ^ 1][j], f[i & 1][j - 1]);
            if (a[i] == b[j])
                f[i & 1][j] = max(f[i & 1][j], f[(i & 1) ^ 1][j - 1] + 1);
        }
    }
    printf("%d\n", n - f[n & 1][n]);
    return 0;
}

标签:Palindrome,1159,5000,int,scanf,short,POJ,字符串,dp
From: https://www.cnblogs.com/zxr000/p/17002482.html

相关文章

  • POJ 1080 Human Gene Functions
    POJ1080HumanGeneFunctions题意:给出两组\(DNA\)序列求它们的最大相似度每个字母与其他字母或自身和空格对应都有一个打分,求在这两个字符串中插入空格,让这两个字......
  • POJ 3176 Cow Bowling
    POJ3176CowBowling题意:给出一个数字三角形,每个分叉路口可以选择一条道路向下走,获得路上的点的权值。求可以获得的最大权值是多少?思路:从上向下走和从下向上走是一......
  • POJ 1163 The Trangle
    POJ1163TheTrangle题意:给出一个数字三角形,每个分叉路口可以选择一条道路向下走,获得路上的点的权值。求可以获得的最大权值是多少?定义状态:我们需要知道当每个位置......
  • POJ 3278 Catch That Cow(BFS)
    POJ3278CatchThatCow​ 现在你在一个数轴上的位置x,位置k上有一头牛,你要抓住这头牛,也就是走到位置k上。那怎么走呢?你有两种走路的方法,一种是从x移动到\(2\tim......
  • POJ-1088 滑雪
    POJ-1088滑雪有一个平面区域,上面有一些点,每个点对应一定的权值,每次移动只能从当前位置向上下左右四个方向中,权值小于当前位置权值的点移动,一次性最多可以移动多远(相邻位......
  • POJ-2533 Longest Ordered Subsequence
    POJ-2533LongestOrderedSubsequence题意:给出一个序列,求出这个序列的最长上升子序列序列\(A\)的上升子序列\(B\)定义如下:\(B\)为\(A\)的子序列\(B\)为严......
  • POJ-1458 Common Subsequence
    POJ-1458CommonSubsequence题意:首先对最长子序列有个定义:如果一个字符串a可以由另一个字符串b删去某些元素得到,那么说明a就是b的子序列字符串现在有两个字符串,请问最......
  • [算法][解析几何]覆盖最多点固定半径圆问题 POJ1981 圆的扫描线 详细解法
    引题: 覆盖最多点固定半径圆问题改编自POJ1981CircleandPoint 背景:在二维平面中给定n个点,求半径为r的圆最多可以覆盖多少个点(1<=n<=300,精度eps=0.0001)输入......
  • 构建一个应用程序,用于在基于内存的数据库中存储 POJO(普通旧 Java 对象)
    本指南将引导您完成构建应用程序的过程,该应用程序使用SpringDataJPA在关系数据库中存储和检索数据。您将构建什么您将构建一个应用程序,用于在基于内存的数据库中存储PO......
  • POJ 2249 : Remmarguts' Date
    #include<iostream>#include<queue>#include<vector>usingnamespacestd;constintN=100000*2+1;#definempmake_pair#definepiipair<int,int>......