一、DP问题
【2011-1】DP-最长公共子序列LCS
问题描述:输入3个子串, 输出这3个子串的最大公共子串
输入:
abcd acb abc
输出:
ab
注意:
(1)输入的字符数组以及dp数组应定义在main函数以外(全局)
(2)由于题意求的是公共字符串,而非字符串长度,因此dp数组应为string类型
#include <iostream>
#include <string.h>
#include <string>
#include <algorithm>
using namespace std;
const int maxn=35;
char a[maxn],b[maxn],c[maxn];
string dp[maxn][maxn][maxn]; //易错点
int main(){
cin>>(a+1)>>(b+1)>>(c+1);
int len1=strlen(a+1);
int len2=strlen(b+1);
int len3=strlen(c+1);
//边界
for(int i=0;i<=len1;i++){
for(int j=0;j<=len2;j++){
for(int k=0;k<=len3;k++){
dp[i][j][0]="";
dp[i][0][k]="";
dp[0][j][k]="";
}
}
}
//状态转移方程
for(int i=1;i<=len1;i++){
for(int j=1;j<=len2;j++){
for(int k=1;k<=len3;k++){
if(a[i]==b[j]&&a[i]==c[k]){
dp[i][j][k]=dp[i-1][j-1][k-1]+a[i];
}else{
int l1=dp[i-1][j][k].length();
int l2=dp[i][j-1][k].length();
int l3=dp[i][j][k-1].length();
if(l1==max(l1,max(l2,l3))){
dp[i][j][k]=dp[i-1][j][k];
}else if(l2==max(l1,max(l2,l3))){
dp[i][j][k]=dp[i][j-1][k];
}else{
dp[i][j][k]=dp[i][j][k-1];
}
}
}
}
}
cout<<dp[len1][len2][len3]<<endl;
return 0;
}
【2014-2】DP-字符串的编辑距离
题目描述:
把两个字符串变成相同的三个基本操作定义如下:
1.修改一个字符(如把a 变成b)
2.增加一个字符(如abed 变成abedd)
3.删除一个字符(如jackbllog 变成jackblog)
针对于jackbllog 到jackblog 只需要删除一个或增加一个l 就可以把两个字符串变为相同。
把这种操作需要的最小次数定义为两个字符串的编辑距离L。
编写程序计算指定文件中字符串的距离。输入两个长度不超过512 字节的ASCII 字符串,在
屏幕上输出字符串的编辑距离。
输入:
Hello world!
Hello word!
输出:
1
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
const int maxn=10010;
int dp[maxn][maxn];
string a,b;
int main(){
getline(cin,a);
getline(cin,b);
int len1=a.size();
int len2=b.size();
//边界
for(int i=0;i<=len1;i++){
dp[i][0]=i;
}
for(int j=0;j<=len2;j++){
dp[0][j]=j;
}
//状态转移方程
for(int i=1;i<=len1;i++){
for(int j=1;j<=len2;j++){
int flag=0;
if(a[i-1]!=b[j-1]){
flag=1;
}
dp[i][j]=min(dp[i-1][j-1]+flag,min(dp[i-1][j]+1,dp[i][j-1]+1));
}
}
cout<<dp[len1][len2]<<endl;
return 0;
}
【2014-4】DP-Hanoi 塔
问题描述
Hanoi 塔问题是印度的一个古老的传说。开天辟地的神勃拉玛在一个庙里留下了三根金刚石的棒,第一根上面套着64 个圆的金片,最大的一个在底下,其余一个比一个小,依次叠上去,庙里的众僧不倦地把它们一个个地从这根棒搬到另一根棒上,规定可利用中间的一根棒作为帮助,但每次只能搬一个,而且大的不能放在小的上面。
请编写程序,把A 柱上的n 个金片,搬动到C 柱(中间可以使用B 柱),使得搬动的次数最少。输入金片的个数n(1<=n<=64),输出总搬动次数,以及最后100 次搬动。如果搬动次数小于等于100 则全部输出;每个搬动占一行,加上是这第几次搬动的数字和”:”,格式见示例。
输入:
2
输出:
3
1:A->B
2:A->C
3:B->C
#include<iostream>
#include<math.h>
using namespace std;
int acount=1,count=0;
void hanoi(int n,char a,char b,char c){
if(n==1){
if((acount-count++)<=100){
cout<<count<<":"<<a<<"->"<<c<<endl;
}
}else{
hanoi(n-1,a,c,b);
if((acount-count++)<=100){
cout<<count<<":"<<a<<"->"<<c<<endl;
}
hanoi(n-1,b,a,c);
}
}
int main()
{
int n;
cin>>n;
for(int i=0;i<n;i++){
acount*=2;
}
acount--;
cout<<acount<<endl;
hanoi(n,'A','B','C');
return 0;
}
【2016-1】DP-求最大连续公共字串长度
题目描述:给定两个字符串,求最大公共字串的长度,长度小于1000
分为两种问题:要求计算连续最长字串的长度
如下按照寻找连续的字串理解
输入:
1111hello2222
1133hello444
输出:
5
注意:公共子串是连续的,如果求不连续,用算法笔记上P435的做法
#include <string>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 1000;
int dp[N][N] = {
0};
int main(){
string A, B;
getline(cin, A);
getline(cin, B);
int l1 = A.length();
int l2 = B.length();
int ans = 0;
for(int i = 0; i < l1; i++){
for(int j = 0; j < l2; j++){
if(A[i] != B[j]){
//两个字符不同
dp[i][j] = 0;
}
else if(i == 0 || j == 0){
//字符相同,而且是第一个字符
dp[i][j] = 1;
if(ans < 1)
ans = 1;
}
else{
//字符相同,均不是第一个字符
dp[i][j] = dp[i - 1][j - 1] + 1;
if(dp[i][j] > ans){
ans = dp[i][j];
}
}
}
}
cout << ans << endl;
return 0;
}
【2018-3】DP-斐波那契数列
问题描述:有2n 的地板,用12和 2*1 的骨牌进行铺地板。问共有多少种情况。结果对 999983 取余,1<=n<=10000
输入:
6
输出:
13
#include<iostream>
using namespace std;
const int maxn=10010;
int dp[maxn];
int main()
{
int n;
cin>>n;
dp[1]=1;
dp[2]=2;
for(int i=3;i<=n;i++){
dp[i]=dp[i-2]+dp[i-1]%999983;
}
cout<<dp[n]<<endl;
return 0;
}
【2019-2】DP-最大连续子序列和
题目描述:给定一个数组及其大小,数组元素在[-106,106],元素个数最多 10^6 个。输出最大的连续子序列和,题目保证最后结果为正数。
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=1000010;
int A[maxn],dp[maxn];
int main()
{
int n;
cin>>n;
for(int i=0;i<n;i++){
cin>>A[i];
}
//边界
dp[0]=A[0];
for(int i=1;i<n;i++){
//状态转移方程
dp[i]=max(A[i],dp[i-1]+A[i]);
}
int max=0;
for(int i=0;i<n;i++){
if(dp[i]>max){
max=dp[i];
}
}
if(max>0)
cout<<max<<endl;
else
cout<<"No existence"<<endl;
return 0;
}
二、二叉树问题
【2011-2】中序与后序求层次遍历
问题描述:输入树的中序和后序排列,输出树的层次遍历
输入:
7
2 3 1 5 7 6 4
1 2 3 4 5 6 7
输出:
4 1 6 3 5 7 2
#include <stdio.h>
#include <queue>
using namespace std;
struct node{
int data;
node* lchild;
node* rchild;
};
int n,post[35],in[35];
node* create(int postL,int postR,int inL,int inR){
//后序和中序构造二叉树
if(postL>postR){
return NULL;
}
node* root=new node;
root->data=post[postR];
int k;
for(k=inL;k<=inR;k++){
if(in[k]==post[postR])
break;
}
int numleft=k-inL;
root->lchild=create(postL,postL+numleft-1,inL,k-1);
root->rchild=create(postL+numleft,postR-1,k+1,inR);
return root;
}
int num=0;
void LayerOrder(node* root){
//层序遍历
queue<node*> q;
q.push(root);
while(!q.empty()){
node