“将A串变为B串”类动态规划题(已修改解释)
来源:互联网 发布:服装et软件cad 编辑:程序博客网 时间:2024/05/18 13:42
今天考试感觉要被虐爆了
就我的感觉来说,后两题绝对是省队水平 Orz Owen第四题考场50‘
不过成绩也不是很差
得益于AC了第一题吧
先给出一道很久以前刷的题目
字符串是数据结构和计算机语言里很重要的数据类型,在计算机语言中,对于字符串我们有很多的操作定义,因此我们可以对字符串进行很多复杂的运算和操作。实际上,所有复杂的字符串操作都是由字符串的基本操作组成。例如,把子串 a 替换为子串 b,就是用查找、删除和插入这三个基本操作实现的。因此,在复杂字符串操作的编程中,为了提高程序中字符操作的速度,我们就应该用最少的基本操作完成复杂操作。 在这里,假设字符串的基本操作仅为:删除一个字符、插入一个字符和将一个字符修改成另一个字符这三种操作。 我们把进行了一次上述三种操作的任意一种操作称为进行了一步字符基本操作。 下面我们定义两个字符串的编辑距离:对于两个字符串 a 和 b,通过上述的基本操作,我们可以把 a 变成 b 或 b 变成 a;那么,把字符串 a 变成字符串 b 需要的最少基本字符操作步数称为字符串 a 和字符串 b 的编辑距离。 例如,如 a=“ABC”,b=“CBCD”,则 a 与 b 的编辑距离为 2。 你的任务就是:编一个最快的程序来计算任意两个字符串的编辑距离。 输入数据: 第 1 行为字符串 a;第 2 行为字符串 b。注:字符串的长度不大于 1000,字符串中的字符全为大写字母。 输出数据: 编辑距离。 样例 输入文件名:edit.in ABC CBCD 输出文件名:edit.out 2
f[i][j]表示第一个串0-i、第二个串0-j之间的编辑距离,按照删除、插入、替换转移即可
code如下#include <cstdio>#include <cstdlib>#include <cstring>#include <iostream>using namespace std;const int maxn = 1000 + 5;int len1, len2;int f[maxn][maxn];char s1[maxn], s2[maxn];void init(),work();int Min(int a,int b,int c,int d) {int mix = (a) < (b) ? (a) : (b);mix = (mix) < (c) ? (mix) : (c); mix = (mix) < (d) ? (mix) : (d);return mix;}int main(){ freopen("edit.in","r",stdin); freopen("edit.out","w",stdout); init(); work(); return 0;}void init(){ scanf("%s\n",s1); scanf("%s\n",s2); len1 = (int) strlen(s1); len2 = (int) strlen(s2); memset(f, 127, sizeof(f)); if (s1[0] == s2[0]) { f[0][0] = 0; for (int i = 1; i <= len1 - 1; ++i) f[i][0] = i; for (int j = 1; j <= len2 - 1; ++j) f[0][j] = j; } else { f[0][0] = 1; if (s1[1] == s2[0]) f[1][0] = 1; else f[1][0] = 2; if (s1[0] == s2[1]) f[0][1] = 1; else f[0][1] = 2; }}void work(){ for (int i = 1;i <= len1 - 1; ++i) for (int j = 1;j <= len2 - 1; ++j) { if (s1[i] == s2[j]) f[i][j] = Min(f[i][j], f[i - 1][j] + 1,f[i][j - 1] + 1, f[i - 1][j - 1]); else if (s1[i]!=s2[j]) f[i][j] = Min(f[i][j], f[i - 1][j] + 1, f[i][j - 1] + 1,f[i - 1][j - 1] + 1); }cout << f[len1 - 1][len2 - 1];}
然后在说今天考试的第一题
与编辑距离差别不大,A的人少其实我也很纳闷
第一题:盾盾的打字机(drdrd) 【题目描述】 盾盾有一个非常有意思的打字机,现在盾哥要用这台打字机来打出一段文章。 由于有了上次的经验,盾盾预先准备好了一段模板 A 存在了内存中,并以此为基础来打出文章 B。盾盾每次操作可以将内存中的某一个字符改成另一个字符,或者在某一个位置插入一个字符,或者删除某一个位置上的字符。另外,为了避免自己预存的模板太腿反而浪费时间,盾哥在所有操作之前会斟酌一下选择留下模板 A 的某一个最优的子串以保证操作次数尽量少(当然盾盾也可以全保留或一个都不留),这一步不计入操作次数。 试求盾盾要打出文章 B 的最少操作次数。 子串是指母串中连续的一段。 【输入数据】 输入包含多组数据。 对于每组数据,两行,分别表示 A 和 B。 【输出数据】 每组数据一行,一个数,表示最少操作次数。 【输入样例】 aaaaa aaa abcabc bcd abcdef klmnopq 【输出样例】 0 1 7 【数据约定】 30% : |A|, |B| <= 10 100% : 1 <= |A|, |B| <= 1000, 数据组数 <= 10, 输入的串中只包含小写字母
code
#include <cstdio>#include <string>#include <cstdlib>#include <iostream>#include <algorithm>using namespace std;#define str stringconst int maxlen = 1000 + 5;str st1, st2;int tot, f[maxlen][maxlen];int Min(int a, int b) { return a < b ? a : b; }int main(){ freopen("drdrd.in", "r", stdin); freopen("drdrd.out", "w", stdout); while (cin >> st1 >> st2) { memset(f, 127, sizeof(f)); int len1 = (int) st1.size(), len2 = (int) st2.size(); for (int i = 0; i <= len1; ++i)//注意检查边界条件 { f[i][0] = 0; for (int j = 0; j <= len2; ++j) f[i + 1][j + 1] = Min(f[i + 1][j + 1], f[i][j] + (st1[i] != st2[j])), i < len1 ? f[i + 1][j] = Min(f[i + 1][j], f[i][j] + 1) : 0, j < len2 ? f[i][j + 1] = Min(f[i][j + 1], f[i][j] + 1) : 0; } tot = INT_MAX; for (int i = 0; i <= len1; ++i) tot = Min(tot, f[i][len2]); cout << tot << endl; } return 0;}
但是此题与编辑距离在输出结果时不同,取了min值
为什么呢?
“盾哥在所有操作之前会斟酌一下选择留下模板 A 的某一个最优的子串以保证操作次数尽量少(当然盾盾也可以全保留或一个都不留),这一步不计入操作次数”
即在我们做出所有操作之前(最开始)我们可以先处理A
且因为有“子串是指母串连续的一段”,即我们对第一个串只能从两头开始删(而不是从中间删)
所以有
for (int i = 0; i <= len1; ++i)
tot = Min(tot, f[i][len2]);
即处理了仅从A串的 1-i 变为B串,A串后全默认删除并找到min值
但似乎枚举也只处理了删除A串后面某段的情况而没有处理一开始就删除A串前面的某段
而实际上,初值f[i][0]=0,即默认A串前i个已经被删除才继续转移的
理解这点后,此题至此完美解决。
- “将A串变为B串”类动态规划题(已修改解释)
- 动态规划题:把一个字符串变为回文串
- 编辑距离:动态规划【用最少的字符操作将字符串A 转换为字符串B】
- 动态规划之编辑距离:用最少的字符操作将A变换成B
- 动态规划求解-将字符串A变换为字符串B 所用的最少字符操作次数
- 【CQOI2013】二进制a+b 动态规划
- 动态规划 day14 B题
- 3-6(修改的)(将字母变为大写)
- 动态规划-请编写一个高效算法,判断C串是否由A和B交错组成。
- MOOC清华《程序设计基础》第6章第2题:求f(a,b)问题(动态规划)
- CI5.5-计算将整数A变为整数B需要改变的二进制位数
- A、B C类网解释
- codeforce 416/B 动态规划简单题
- 543A - Writing Code (动态规划)
- CodeForces 698A Vacations (动态规划)
- CodeForces 455A:Boredom (动态规划)
- HDU5492 Find a path (动态规划)
- hdoj动态规划A
- 28个Unix/Linux的命令行神器
- Android Init Language,init.rc的语法结构说明
- Android杂谈---获取手机屏幕大小
- Eclipse在线调试ARM11——Tiny6410+OpenJTAG
- linux下oracle数据文件管理操作命令
- “将A串变为B串”类动态规划题(已修改解释)
- VC++动态链接库(DLL)编程
- Android Service
- http://www.cs.cmu.edu/puzzle/puzzle2.html
- POJ 1151 Atlantis 离散化 + 扫描线 + 线段树
- 关于程序人生的思考
- java-不可变字符串
- 657 - The die is cast
- bind2nd使用