关于回文串的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]改为同一字符
- 第一种情况是,想要将(i,j)变为回文串,可以是在(i+1,j)已是回文串的基础上,在j后面添加字符 s[i],或者直接将i处的字符 s[i] 删掉,取代价小的操作即可
- 另一种情况是,如果(i,j-1)是回文串,可以将j处的字符删掉或在i前面填加字符s[j],同样取代价小的方式操作
Code:提供几种不同的写法,加深理解
#include <stdio.h>
#include <string.h>
#define mem(a) memset(a,0,sizeof(a))
#define MIN(a,b) ((a) < (b) ? (a) : (b)) int DP[][],cost[],N,M;
char str[]; int main()
{
while(~scanf("%d%d", &M, &N))
{
mem(DP); mem(str); mem(cost);
scanf("%s%*c",str);
char ch; int x, y;
for(int i=;i<M;i++)
{
scanf("%c %d %d%*c", &ch, &x, &y);
cost[ch-'a'] = MIN(x,y);
}
for(int i=;i<N;i++)
{
for(int j=i-;j>=;j--)
{
DP[j][i] = MIN(DP[j+][i]+cost[str[j]-'a'], DP[j][i-]+cost[str[i]-'a']);
if(str[i] == str[j])DP[j][i] = MIN(DP[j][i],DP[j+][i-]);
}
}
printf("%d\n", DP[][N-]);
}
return ;
}
1
#include<iostream>
#include<algorithm>
using namespace std;
typedef pair<int, int> P;
#define ad first
#define de second
int n, m, dp[][];
char s[];
P ch[]; //ch[ch-'a'].ad代表add一个ch的代价,ch[ch-'a'].de代表delete一个ch的代价
int main()
{
cin >> n >> m >> s;
for (int i = ; i <= n; i++)
{
char Ch;
cin >> Ch;
cin >> ch[Ch - 'a'].ad >> ch[Ch - 'a'].de;
}
for (int i = ; i <= m; i++)
dp[i][i] = ;
for (int i = ; i < m; i++) //注意for循环要实现从短串到长串的过渡,这里i代表长度为i+1
for (int j = ; j + i < m; j++)
if (s[j] == s[j + i]) dp[j][j + i] = dp[j + ][j + i - ];
else
{
int aa = dp[j + ][j + i] + min(ch[s[j] - 'a'].ad, ch[s[j] - 'a'].de);
int bb = dp[j][j + i - ] + min(ch[s[j + i] - 'a'].ad, ch[s[j + i] - 'a'].de);
dp[j][j + i] = min(aa, bb);
}
printf("%d\n", dp[][m - ]);
return ;
}
2
#include <cstdio>
#include <string>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = ;
const int M = ;
int add[N];
int dp[M][M]; int main()
{
int n,m;
string s;
while(~scanf("%d%d",&n,&m))
{
cin>>s;
char c;int x,y;
for(int i=;i<n;i++)
{
cin>>c>>x>>y;
add[c]=min(x,y);
}
memset(dp,,sizeof(dp));
for(int k=;k<s.size();k++)
{
for(int i=,j=k;j<s.size();i++,j++)
{
dp[i][j]=0x3f3f3f3f;
if(s[i]==s[j])
dp[i][j]=dp[i+][j-];
else
{
dp[i][j]=min(dp[i+][j] + add[s[i]],dp[i][j]);
dp[i][j]=min(dp[i][j-] + add[s[j]],dp[i][j]);
}
}
}
printf("%d\n",dp[][s.size()-]);
}
return ;
}
3
问题2:插入最少多少个字符使得原字符串变成一个回文串
poj 1159 Palindrome
Sol:
首先第一种方法是:
这道题相当于是上一个题中的修改代价为1的情况
因此列出方程:

从上面的分析可以看出,这个问题的实质是求最长公共子序列,只是这两个序列分别是串S的前一部分和串S后一部分的逆序列。
由此引出第二种方法
第二种方法:
先说结论:设原序列S的逆序列为S',最少需要补充的字母数 = 原序列S的长度-S和S'的最长公共子串长度
最后这道题需要对内存进行优化
Code:
#include <iostream>
#include <cstdio>
#include <cstring> using namespace std; #define MIN(a, b) ((a) < (b) ? (a) : (b)) #define MAXSIZE 5005 //开始没有考虑内存问题,使用了int型,超内存限制,也可使用滚动数组解决
unsigned short d[MAXSIZE][MAXSIZE]; int ToPalindrome(char *s, int n)
{
int i, j, k;
//只有一个字符时,不需要添加字符
for (i = ; i < n; i++)
{
d[i][i] = ;
}
//串长度为2时
for (i = ; i < n; i++)
{
if (s[i-] == s[i])
{
d[i-][i] = ;
}
else
{
d[i-][i] = ;
}
} //串长度递增
for (k = ; k < n; k++)
{
for (i = , j = k; j < n; i++, j++)
{
if (s[i] == s[j])
{
d[i][j] = d[i+][j-];
}
else
{
d[i][j] = MIN(d[i][j-], d[i+][j]) + ;
}
}
}
return d[][n-];
} int main(void)
{
char str[MAXSIZE]; int n;
while (scanf("%d", &n) != EOF)
{
getchar();
gets(str);
printf("%d\n", ToPalindrome(str, n));
}
return ;
}
1
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std; const int N=;
int n;
char a[N],b[N];
int f[][N]; int main(){
while(scanf("%d",&n)!=EOF){
scanf("%s",a+);
for(int i=;i<=n;++i)
b[i]=a[n-i+];
memset(f,,sizeof(f));
for(int i=;i<=n;++i)
for(int j=;j<=n;++j)
if(a[i]==b[j]) f[i%][j]=f[(i-)%][j-]+;
else f[i%][j]=max(f[(i-)%][j],f[i%][j-]);
printf("%d\n",n-f[n%][n]);
}
return ;
}
2
关于回文串的DP问题的更多相关文章
- 【GDOI2016模拟3.15】基因合成(回文串+性质+DP)
[GDOI2016模拟3.15]基因合成 题意: 给一个目标串,要求从空串进行最少的操作次数变成目标串,操作有两种: 在串的头或尾加入一个字符. 把串复制一遍后反向接到串的末尾. 因为有回文操作,所以 ...
- 回文串 --- 动态dp UVA 11584
题目链接: https://cn.vjudge.net/problem/34398/origin 本题的大意其实很简单,就是找回文串,大致的思路如下: 1. 确定一个回文串,这里用到了自定义的chec ...
- poj3280 Cheapest Palindrome(回文串区间dp)
https://vjudge.net/problem/POJ-3280 猛刷简单dp第一天第三题. 这个据说是[求字符串通过增减操作变成回文串的最小改动次数]的变体. 首先增减操作的实质是一样的,所以 ...
- 1154 回文串划分(DP+Manacher)
1154 回文串划分 基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题 有一个字符串S,求S最少可以被划分为多少个回文串. 例如:abbaabaa,有多种划分方式. ...
- uva 10453 【回文串区间dp】
Uva 10453 题意:给定字符串,问最少插入多少个字符使其变成回文串,并任意输出一种结果. 题解:和Uva 10739类似,这里是只能增加.类似定义dp[i][j]表示子串Si...Sj变为回文串 ...
- [LeetCode] Palindrome Partitioning 拆分回文串
Given a string s, partition s such that every substring of the partition is a palindrome. Return all ...
- 计蒜之道 初赛 第三场 题解 Manacher o(n)求最长公共回文串 线段树
腾讯手机地图 腾讯手机地图的定位功能用到了用户手机的多种信号,这当中有的信号的作用范围近.有的信号作用的范围则远一些.有的信号相对于用户在不同的方位强度是不同的,有的则是在不论什么一个方向上信号强度都 ...
- NYOJ 1023 还是回文(DP,花最少费用形成回文串)
/* 题意:给出一串字符(全部是小写字母),添加或删除一个字符,都会产生一定的花费. 那么,将字符串变成回文串的最小花费是多少呢? 思路:如果一个字符串增加一个字符 x可以形成一个回文串,那么从这个字 ...
- poj 1159 dp回文串
题意:添加最少的字符使之成为回文串 #include<cstdio> #include<iostream> #include<algorithm> #include ...
随机推荐
- luogu P1361 小猫爬山 [iddfs]
题目描述 WD和LHX饲养了N只小猫,这天,小猫们要去爬山.经历了千辛万苦,小猫们终于爬上了山顶,但是疲倦的它们再也不想徒步走下山了. WD和LHX只好花钱让它们坐索道下山.索道上的缆车最大承重量为W ...
- servlet前台中文参数处理
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletExcep ...
- java 常见数据结构
1)tree 2) queue 3) list 4) stack 5) heap 6) map
- 40. leetcode 202. Happy Number
Write an algorithm to determine if a number is "happy". A happy number is a number defined ...
- 笔记本电脑连接上WiFi后,弹不出登录界面怎么办?
以CMCC为例子 步骤: 1 连接成功CMCC之后,打开适配器设置.右击无线网卡,选择属性 2.双击INTERNET协议版本4 3.将DNS改成自动获取,然后确定 4.再确定 5.然后重新断开CMCC ...
- C#和NewSQL更配 —— CockroachDB入门(可能是C#下的全网首发)
阅读目录 CockroachDB是什么 环境部署 实战 性能测试 结语 一.CockroachDB是什么 CockroachDB(https://www.cockroachlabs.com)是Goog ...
- solr排序问题
搜搜引擎排序问题,因为涉及到的维度比较多,有时候单纯的依靠sort是无法满足需要的,例如:搜索商品的时候我希望不管怎么排无货的商品都置底,这样问题就来了,怎么排? 其实,solr是自己的解决 ...
- 阅读:DBA们不得不知的数据库硬件RAID常识
对于数据库这种特殊应用IOPS往往会成为瓶颈,突破的这个瓶颈的有效方法不多,软件方面主要是读写分离,垂直拆分,分区表技术,cluster.硬件方面主要是raid,和SSD. 通常都是软件和硬件同时优化 ...
- 切换Ubuntu系统python默认版本的方法
另附切换系统python默认版本的方法: 先使用命令: update-alternatives --list python 查看python命令的各种可能结果, 例如我的结果: /usr/bin/py ...
- SQL查询操作及子句优先级
用source .sql文件竟然可以自动建表. 简单数据查询: select * from table_name; 避免重复查询: select distinct(field_name) from t ...