LightOJ1033 Generating Palindromes(区间DP/LCS)

题目要计算一个字符串最少添加几个字符使其成为回文串。

一年多前,我LCS这道经典DP例题看得还一知半解时遇到一样的问题,http://acm.fafu.edu.cn/problem.php?id=1007

当时完全靠自己瞎YY出了LCS的解法:

我当时这么想的:

  • 把字符串分成两个部分,假设这两个部分分别就属于新的回文串的对称的两部分,那么要添加最少的字符串形成回文串就需要前一部分和后一部分公共部分最多,也就是它们的(一正一反)LCS。
  • 这样就是枚举中间部分的位置(另外还要分情况讨论奇数和偶数回文串,奇数的枚举的就是中间元素的位置),然后计算两个部分的长度-2*LCS(一正一反),取最小的。
  • 两个部分的长度的(一正一反)LCS可以通过计算原字符串和其反转串的LCS预处理出来,就是dp[i][j]的意义——s11...s1i和s21...s2j的LCS。

我搜了下,真有LCS的解法,不过不一样的是很简单就是长度-LCS就是解。真难想象当时能完全靠自己想出这个解法的我。。

现在做这题,就想到区间DP,然后搞了下就AC了,虽然状态转移只是靠着感觉去写,正确性一知半解。。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 #define INF (1<<29)
 6 int d[222][222];
 7 char str[222];
 8 int main(){
 9     int t;
10     scanf("%d",&t);
11     for(int cse=1; cse<=t; ++cse){
12         scanf("%s",str);
13         int n=strlen(str);
14         for(int i=0; i<n; ++i){
15             for(int j=i+1; j<n; ++j) d[i][j]=INF;
16             for(int j=0; j<=i; ++j) d[i][i]=0;
17         }
18         for(int len=2; len<=n; ++len){
19             for(int i=0; i+len<=n; ++i){
20                 if(str[i]==str[i+len-1]) d[i][i+len-1]=d[i+1][i+len-2];
21                 else{
22                     for(int j=i; j<i+len-1; ++j) d[i][i+len-1]=min(d[i][i+len-1],d[i][j]+i+len-1-j);
23                     for(int j=i+len-1; j>i; --j) d[i][i+len-1]=min(d[i][i+len-1],d[j][i+len-1]+j-i);
24                 }
25             }
26         }
27         printf("Case %d: %d\n",cse,d[0][n-1]);
28     }
29     return 0;
30 }
时间: 2024-10-10 01:55:29

LightOJ1033 Generating Palindromes(区间DP/LCS)的相关文章

Light OJ 1033 - Generating Palindromes(区间DP)

题目大意: 给你一个字符串,问最少增加几个字符使得这个字符串变为回文串. ======================================================================================= #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<cmath> #include&l

「Codeforces」245H Queries for Number of Palindromes (区间dp)

题意:原题在这 You've got a string s = s1s2... s|s| of length |s|, consisting of lowercase English letters. There also are q queries, each query is described by two integers li, ri (1 ≤ li ≤ ri ≤ |s|). The answer to the query is the number of substrings of

codeforces 245H H. Queries for Number of Palindromes(区间dp)

题目链接: codeforces 245H 题目大意: 给出一个字符串,询问任意区间内的回文子串的个数. 题目分析: 定义isPar[i][j]表示区间字符串[i,j]是否是回文,可以通过isPar[i+1][j-1]递推得到. 定义dp[i][j]表示及区间[i,j]内的回文子串的个数,转移方程如下: dp[i][j]=dp[i+1][j]+dp[i][j?1]?dp[i+1][j?1]+isPar[i][j] 用到了一点容斥的思想. AC代码: #include <iostream> #i

区间DP UVA 11584 Partitioning by Palindromes

题目传送门 1 /* 2 题意:给一个字符串,划分成尽量少的回文串 3 区间DP:状态转移方程:dp[i] = min (dp[i], dp[j-1] + 1); dp[i] 表示前i个字符划分的最少回文串, 4 如果s[j] 到 s[i]是回文串,那么可以从dp[j-1] + 1递推过来 5 */ 6 #include <cstdio> 7 #include <cstring> 8 #include <algorithm> 9 #include <cmath&g

简单Dp----最长公共子序列,DAG最长路,简单区间DP等

/* uva 111 * 题意: * 顺序有变化的最长公共子序列: * 模板: */ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int a[100]; int mu[100]; int Dp[100][100]; int main() { int n,x; scanf("%d", &n

区间DP基础篇之 POJ1159——Palindrome

题目大意:给定一个字符串,求最少插入几个字符让该字符串成为回文串 法一: dp[i][j]表示使区间[i,j]成为回文串最小插入的字符数,则状态转移方程 1.if s[i]==s[len-1] 则:d[i][j]=d[i+1][j-1] 2.else  d[i]=min(dp[i+1][j],dp[i][j-1]) 首尾字符不同的时候,有两种决策. 1.将新字符插在首位,那么状态就变成了dp[i+1][j]了. 2.将新字符插在末尾,则状态就变成了dp[i][j-1]了 .比较两种决策哪种更优就

UVA 11404 Palindromic Subsequence[DP LCS 打印]

UVA - 11404 Palindromic Subsequence 题意:一个字符串,删去0个或多个字符,输出字典序最小且最长的回文字符串 不要求路径区间DP都可以做 然而要字典序最小 倒过来求LCS,转移同时维护f[i][j].s为当前状态字典序最小最优解 f[n][n].s的前半部分一定是回文串的前半部分(想想就行了) 当s的长度为奇时要多输出一个(因为这样长度+1,并且字典序保证最小(如axyzb  bzyxa,就是axb)) // // main.cpp // uva11404 //

POJ 1159 Palindrome(区间DP/最长公共子序列+滚动数组)

Palindrome Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 56150   Accepted: 19398 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

HDU 4745 Two Rabbits (区间DP)

题意:给定一个圆形的环,有两个只兔子,一只顺时针跳,一个逆时针,但每次跳到的石头必须一样,问你最多能跳多少轮. 析:本来以为是LCS呢,把那个序列看成一个回文,然后就能做了,但是时间受不了.其实是一个区间DP,dp[i[j] 表示从 i 到 j 中最长的回文数. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include <string> #in