贪心算法
1.跳跳
题目描述
你是一只小跳蛙,你特别擅长在各种地方跳来跳去。
这一天,你和朋友小 F 一起出去玩耍的时候,遇到了一堆高矮不同的石头,其中第 i i i 块的石头高度为 h i h_i hi,地面的高度是 h 0 = 0 h_0 = 0 h0=0。你估计着,从第 i i i 块石头跳到第 j j j 块石头上耗费的体力值为 ( h i − h j ) 2 (h_i - h_j) ^ 2 (hi−hj)2,从地面跳到第 i i i 块石头耗费的体力值是 ( h i ) 2 (h_i) ^ 2 (hi)2。
为了给小 F 展现你超级跳的本领,你决定跳到每个石头上各一次,并最终停在任意一块石头上,并且小跳蛙想耗费尽可能多的体力值。
当然,你只是一只小跳蛙,你只会跳,不知道怎么跳才能让本领更充分地展现。
不过你有救啦!小 F 给你递来了一个写着 AK 的电脑,你可以使用计算机程序帮你解决这个问题,万能的计算机会告诉你怎么跳。
那就请你——会写代码的小跳蛙——写下这个程序,为你 NOIp AK 踏出坚实的一步吧!
输入格式
输入一行一个正整数 n n n,表示石头个数。
输入第二行 n n n 个正整数,表示第 i i i 块石头的高度 h i h_i hi。
输出格式
输出一行一个正整数,表示你可以耗费的体力值的最大值。
样例 1
样例输入 1
2
2 1
样例输出 1
5
样例 2
样例输入 2
3
6 3 5
样例输出 2
49
提示
样例解释
两个样例按照输入给定的顺序依次跳上去就可以得到最优方案之一。
数据范围
对于 1 ≤ i ≤ n 1 \leq i \leq n 1≤i≤n,有 0 < h i ≤ 1 0 4 0 < h_i \leq 10 ^ 4 0<hi≤104,且保证 h i h_i hi 互不相同。
对于 10 % 10\% 10% 的数据, n ≤ 3 n \leq 3 n≤3;
对于 20 % 20\% 20% 的数据, n ≤ 10 n \leq 10 n≤10;
对于 50 % 50\% 50% 的数据, n ≤ 20 n \leq 20 n≤20;
对于 80 % 80\% 80% 的数据, n ≤ 50 n \leq 50 n≤50;
对于 100 % 100\% 100% 的数据, n ≤ 300 n \leq 300 n≤300。
c++实现
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
int main(){
int a[333];
int n,h=0;
cin>>n;
a[0]=0;
for(int i=1;i<=n;i++){
cin>>a[i];
}
sort(a,a+n+1);
int i=0,j=n;
while(i<j){
h += pow(a[i] - a[j], 2);
i++;
h += pow(a[i] - a[j], 2);
j--;
}
cout<<h;
return 0;
}
2.
题目描述
给出n个正整数,将他们排成一排组成一个最大的正整数。
设计解决这一问题的贪心策略。
#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
/*最大*/
bool cmp1(string a,string b){
return a+b > b+a;
}
/*最小*/
//bool cmp2(string a,string b){
// return a+b<b+a;
//}
int main(){
string a[100000];
int n;
cin>>n;
for(int i=0;i<n;i++){
cin>>a[i];
}
sort(a,a+n,cmp1);
cout<<"Max=";
for(int i=0;i<n;i++){
cout<<a[i];
}
// sort(a,a+n,cmp2);
// cout<<"\tMin=";
// for(int i=0;i<n;i++){
// cout<<a[i];
// }
return 0;
}
DFS(深度优先搜索【回溯算法】)
1.装载问题
给定n个集装箱要装上一艘载重量为c的轮船,其中集装箱i的重量为wi。集装箱装载问题要求确定在不超过轮船载重量的前提下,将尽可能多的集装箱装上轮船(贪心算法中的装载问题讨论的是装载件数;本题讨论的是最大装载重量。)
由于集装箱问题是从n个集装箱里选择一部分集装箱,假设解向量为X(x1, x2, …, xn),其中xi∈{0, 1}, xi =1表示集装箱i装上轮船, xi =0表示集装箱i不装上轮船。
输入
每组测试数据:第1行有2个整数c和n。C是轮船的载重量(0<c<30000),n是集装箱的个数(n≤20)。第2行有n个整数w1, w2, …, wn,分别表示n个集装箱的重量。
输出
对每个测试例,输出两行:第1行是装载到轮船的最大载重量,第2行是集装箱的编号。
样例:
样例输入
34 3
21 10 5
样例输出
31
1 2
#include<bits/stdc++.h>
#define NUM 1000
using namespace std;
int w[NUM]; /*集装箱重量集合*/
int x[NUM]; /*当前搜索的解向量*/
int r; /*剩余集装箱的重量*/
int cw; /*当前轮船的载重量*/
int bestw; /*当前最优载重量*/
int bestx[NUM]; /*当前最优解*/
void BackTrack(int t,int c,int n){
/*到达叶子结点*/
if(t>n){
if(cw>bestw){
/*更新最优解*/
for(int i=1;i<=n;i++){
bestx[i]=x[i];
}
bestw=cw;
}
return;
}
/*更新剩余集装箱的重量*/
r-=w[t];
/*搜索左子树*/
if(cw+w[t]<=c){
x[t]=1;
cw+=w[t];
BackTrack(t+1,c,n);
cw-=w[t];
}
/*搜索右子树*/
if(cw+r>bestw){
x[t]=0;
BackTrack(t+1,c,n);
}
r+=w[t];
}
int main() {
//freopen("in.txt","r",stdin);
int n,c;
cin>>c>>n;
for(int i=1;i<=n;i++){
cin>>w[i];
r+=w[i]; /*初始化剩余集装箱的重量*/
}
BackTrack(1,c,n);
cout<<bestw<<endl;
for(int i=1;i<=n;i++){
if(bestx[i]==1)
cout<<i<<" ";
}
//fclose(stdin);
return 0;
}
2. 0-1背包问题
给定一个物品集合s={1,2,3,…,n},物品i的重量是wi,其价值是vi,背包的容量为W,即最大载重量不超过W。在限定的总重量W内,我们如何选择物品,才能使得物品的总价值最大。
输入:第一个数据是背包的容量为c(1≤c≤1500),第二个数据是物品的数量为n(1≤n≤50)。接下来n行是物品i的重量是wi,其价值为vi。所有的数据全部为整数,且保证输入数据中物品的总重量大于背包的容量。当c=0时,表示输入数据结束。
输出:对每组测试数据,输出装入背包中物品的最大价值。
样例:
输入样例 | 输出样例 |
---|---|
50 3 | 220 |
10 60 30 120 20 100 |
#include<bits/stdc++.h>
#define NUM 1000
using namespace std;
int cw; /*当前重量*/
int cv; /*当前价值*/
int bestv; /*当前最优价值*/
struct goods{
int w; /*物品重量*/
int v; /*物品价值*/
double d; /*物品单位价值重量比*/
}Q[NUM];
bool cmp(goods a,goods b){
return a.d>=b.d;
}
int add(int t,int c,int n){
int cleft=c-cw; /*背包剩余容量*/
int b=cv; /*上界*/
while(t<n&&Q[t].w<=cleft){
cleft-=Q[t].w;
b+=Q[t].v;
t++;
}
if(t<n){
b+=1.0*Q[t].v/Q[t].w;
}
return b;
}
void DFS(int t,int c,int n){
if(t>n){
bestv=cv;
return;
}
if(cw+Q[t].w<=c){
cw+=Q[t].w;
cv+=Q[t].v;
DFS(t+1,c,n);
cw-=Q[t].w;
cv-=Q[t].v;
}
if(add(t+1,c,n)>bestv){
DFS(t+1,c,n);
}
}
int main() {
//freopen("in.txt","r",stdin);
int c,n;
cin>>c>>n;
for(int i=0;i<n;i++){
cin>>Q[i].w>>Q[i].v;
Q[i].d=1.0*Q[i].v/Q[i].w;
}
sort(Q,Q+n,cmp);
DFS(0,c,n);
cout<<bestv<<endl;
//fclose(stdin);
return 0;
}
3.图的m着色问题
给定无向连通图G=(V, E)和m种不同的颜色,用这些颜色为图G的各顶点着色,每个顶点着一种颜色。是否有一种着色法使G中相邻的两个顶点有不同的颜色?
若一个图最少需要m种颜色才能使图中每条边连接的两个顶点着不同颜色,则称这个数m为该图的色数。求一个图的色数m的问题称为图的m可着色优化问题。
编程计算:给定图G=(V, E)和m种不同的颜色,找出所有不同的着色法和着色总数。
输入样例 | 输出样例 |
---|---|
5 4 1 3 1 2 1 4 2 3 2 4 2 5 3 4 4 5 0 0 | 1 2 3 4 1 1 2 3 4 3 1 2 4 3 1 1 2 4 3 4 1 3 2 4 1 1 3 2 4 2 1 3 4 2 1 … 4 3 2 1 4 Total=48 |
#include<bits/stdc++.h>
#define NUM 1000
using namespace std;
int a[NUM][NUM];/*图的邻接矩阵*/
int x[NUM]; /*当前的解向量*/
int sum; /*已经找到的可m着色的方案数量*/
/*将相邻边转化为邻接矩阵*/
void T(int x,int y,int n){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
a[x][y]=1;
a[y][x]=1;
}
}
}
bool Same(int t,int m,int n){
for(int i=1;i<=n;i++){
if((a[t][i]==1)&&(x[i]==x[t])){
return false;
}
}
return true;
}
void DFS(int t,int m,int n){
if(t>n){
sum++;
for(int i=1;i<=n;i++){
cout<<x[i]<<" ";
}
cout<<endl;
}else{
for(int i=1;i<=m;i++){
x[t]=i;
if(Same(t,m,n)){
DFS(t+1,m,n);
}
x[t]=0;
}
}
}
int main() {
//freopen("in.txt","r",stdin);
int m,n,a,b;
cin>>n>>m;
while(cin>>a>>b){
T(a,b,n);
}
DFS(1,m,n);
cout<<"Total="<<sum<<endl;
//fclose(stdin);
return 0;
}
4.n皇后问题
在n×n格的棋盘上放置彼此不受攻击的n个皇后。
按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。
n皇后问题等价于在n×n格的棋盘上放置n个皇后,任何两个皇后不放在同一行或同一列或同一斜线上。
编程要求:找出一个n×n格的棋盘上放置n个皇后并使其不能互相攻击的所有方案。
输入样例 | 输出样例 |
---|---|
5 | 1 3 5 2 4 1 4 2 5 3 2 4 1 3 5 2 5 3 1 4 3 1 4 2 5 3 5 2 4 1 4 1 3 5 2 4 2 5 3 1 5 2 4 1 3 5 3 1 4 2 Total= 10 |
#include<bits/stdc++.h>
#define NUM 1000
using namespace std;
int x[NUM]; /*解向量*/
int sum; /*当前已经找到的可行方案数*/
bool Place(int t){
for(int i=1;i<t;i++){
if((x[i]==x[t])||(abs(t-i)==abs(x[i]-x[t]))){
return false;
}
}
return true;
}
void DFS(int t,int n){
if(t>n){
sum++;
for(int i=1;i<=n;i++){
cout<<x[i]<<" ";
}
cout<<endl;
}else{
for(int i=1;i<=n;i++){
x[t]=i;
if(Place(t)){
DFS(t+1,n);
}
// x[t]=0;
}
}
}
int main() {
//freopen("in.txt","r",stdin);
int n;
cin>>n;
DFS(1,n);
cout<<"Total="<<sum<<endl;
//fclose(stdin);
return 0;
}
BFS(广度优先搜索【分支限界算法】)
1.细胞矩阵
一矩形阵列由数字0到9组成,数字1到9代表细胞数字,细胞的定义为沿细胞数字上下左右还是细胞数字则为同一细胞,求给定矩形阵列的细胞个数。如阵列 :
4 10
0234500067
1034560500
2045600671
0000000089
有4个细胞。
输入
矩阵的行列值 m和n
以及这个矩阵
输出
细胞的个数
样例输入
4 10
0234500067
1034560500
2045600671
0000000089
样例输出
4
【算法分析】
⑴读入m*n矩阵阵列,将其转换为boolean矩阵存入bz数组中;
⑵沿bz数组矩阵从上到下,从左到右,找到遇到的第一个细胞;
⑶将细胞的位置入队h,并沿其上、下、左、右四个方向上的细胞位置入队,入队后的位置bz数组置为false;
⑷将h队的队头出队,沿其上、下、左、右四个方向上的细胞位置入队,入队后的位置bz数组置为false;
⑸重复4,直至h队空为止,则此时找出了一个细胞;
⑹重复2,直至矩阵找不到细胞;
⑺输出找到的细胞数。
#include<bits/stdc++.h>
#define N 1000
using namespace std;
struct site {
int x;
int y;
};
int dx[4]= {-1,0,1,0}; /*上下走*/
int dy[4]= {0,1,0,-1}; /*左右走*/
int bz[N][N]; /*细胞矩阵*/
int ans=0; /*细胞数*/
int m,n; /*矩阵行数、列数*/
void bfs(int p,int q) {
queue<site> qc;
ans++;
site s,f;
s.x=p;
s.y=q;
qc.push(s);
while(!qc.empty()) {
f=qc.front();
qc.pop();
for(int i=0; i<4; i++) {
s.x=f.x+dx[i];
s.y=f.y+dy[i];
if((s.x>=0)&&(s.x<m)&&(s.y>=0)&&(s.y<n)&&(bz[s.x][s.y])) {
qc.push(s);
bz[s.x][s.y]=0;
}
}
}
}
int main() {
//freopen("in.txt","r",stdin);
char s[N];
cin>>m>>n;
cin.get();
for (int i=0; i<m; i++ )
for (int j=0; j<n; j++ )
bz[i][j]=1;
for (int i=0; i<m; i++) {
gets(s);
for (int j=0; j<n; j++)
if (s[j]=='0')
bz[i][j]=0;
}
for (int i=0; i<m; i++)
for (int j=0; j<n; j++)
if (bz[i][j]) {
bz[i][j]=0;
bfs(i,j);
}
cout<<ans<<endl;
//fclose(stdin);
return 0;
}
2.最小步数
在各种棋中,棋子的走法总是一定的,如中国象棋中马走“日”。有一位小学生就想如果马能有两种走法将增加其趣味性,因此,他规定马既能按“日”走,也能如象一样走“田”字。他的同桌平时喜欢下围棋,知道这件事后觉得很有趣,就想试一试,在一个(100*100)的围棋盘上任选两点A、B,A点放上黑子,B点放上白子,代表两匹马。棋子可以按“日”字走,也可以按“田”字走,俩人一个走黑马,一个走白马。谁用最少的步数走到左上角坐标为(1,1)的点时,谁获胜。现在他请你帮忙,给你A、B两点的坐标,想知道两个位置到(1,1)点可能的最少步数。
输入样例
12 16
18 10
输出样例
8 9
#include<bits/stdc++.h>
using namespace std;
struct s{
int x; //横坐标
int y; //纵坐标
int ans;//(1,1)-->(x,y)的步数
};
int x[12]={1,2,2,1,2,2,-1,-2,-2,-1,-2,-2};
int y[12]={2,1,2,-2,-1,-2,2,1,2,-2,-1,-2};
int main(){
int a[101][101];
int m1,n1,m2,n2;
queue<s> q;
s ss,ff;
memset(a,0xff,sizeof(a));
ss.x=ss.y=1;ss.ans=0;
q.push(ss);
cin>>m1>>n1>>m2>>n2;
while(!q.empty()){
ff=q.front();
for(int i=0;i<12;i++){
int dx=ff.x+x[i];
int dy=ff.y+y[i];
if(dx>0&&dy>0&&dx<=100,dy<=100){
if(a[dx][dy]==-1){
a[dx][dy]=ff.ans+1;
ss.x=dx;ss.y=dy;ss.ans=a[dx][dy];
q.push(ss);
if(a[m1][n1]>0&&a[m2][n2]>0){
cout<<a[m1][n1]<<endl;
cout<<a[m2][n2]<<endl;
return 0;
}
}
}
}
q.pop();
}
}
3.装载问题
给定n个集装箱要装上一艘载重量为c的轮船,其中集装箱i的重量为wi。集装箱装载问题要求确定在不超过轮船载重量的前提下,将尽可能多(重量)的集装箱装上轮船。
由于集装箱问题是从n个集装箱里选择一部分集装箱,假设解向量为X(x1, x2, …, xn),其中xi∈{0, 1}, xi =1表示集装箱i装上轮船, xi =0表示集装箱i不装上轮船。
输入:每组测试数据:第1行有2个整数c和n。C是轮船的载重量(0<c<30000),n是集装箱的个数(n≤20)。第2行有n个整数w1, w2, …, wn,分别表示n个集装箱的重量。
输出:对每个测试例,输出装载到轮船的最大载重量
输入样例
80 4
18 7 25 36
输出样例
79
#include<bits/stdc++.h>
#define N 1000
using namespace std;
int cw; /*当前重量*/
int bestw; /*不超过载重量的最大重量*/
int r; /*剩余重量*/
int w[N]; /*集装箱重量*/
int c; /*轮船载重量*/
int n; /*集装箱个数*/
int bfs(){
queue<int> q;
q.push(-1);
int i=0;
for(int j=0;j<n;j++){
r+=w[j];
}
while(1){
int wt=cw+w[i];
if(wt<=c){
if(wt>bestw){
bestw=wt;
}
if(i<n){
q.push(wt);
}
}
if(cw+r>bestw&&i<n){
q.push(cw);
}
cw=q.front();
q.pop();
if(cw==-1){
if(q.empty()){
return bestw;
}
q.push(-1);
cw=q.front();
q.pop();
i++;
r-=w[i];
}
}
return bestw;
}
int main(){
//freopen("in.txt","r",stdin);
cin>>c>>n;
for(int i=0;i<n;i++){
cin>>w[i];
}
cout<<bfs()<<endl;
//fclose(stdin);
return 0;
}
DP(动态规划)
1.数字三角形
数字三角形,从顶部出发,在每一结点可以选择向左走或者向右走,一直走到底层。
试设计一个算法,计算出从三角形的顶至底的一条路径,使该路径经过的数字总和最大。
动态规划方程: a[i][j]=max(a[i+1][j],a[i+1][j+1])
输入样例
6
9
12 15
10 6 8
2 18 9 5
19 7 10 4 16
输出样例
59
#include<bits/stdc++.h>
#define NUM 1000
using namespace std;
int x[NUM][NUM];/*存数字三角形*/
/*向左走i++;向右走i++,j++*/
int add(int n){
for(int i=n-2;i>=0;i--){
for(int j=0;j<=i;j++){
x[i][j]+=max(x[i+1][j],x[i+1][j+1]);
}
}
return x[0][0];
}
int main() {
//freopen("in.txt","r",stdin);
int n;
cin>>n;
for(int i=0;i<n;i++){
for(int j=0;j<i;j++){
cin>>x[i][j];
}
}
cout<<add(n);
//fclose(stdin);
return 0;
}
2.最大子段和
问题: 给定n个整数(可能为负数)组成的序列a[1],a[2],a[3],…,a[n],求该序列如a[i]+a[i+1]+…+a[j]的子段和的最大值。当所给的整数均为负数时定义子段和为0,依此定义,所求的最优值为: Max{0,a[i]+a[i+1]+…+a[j]},1<=i<=j<=n 例如,当(a[1],a[2],a[3],a[4],a[5],a[6])=(-20,11,-4,13,-5,-2)时,最大子段和为20。
输入
输入n及n个数
输出
子段和的最大值
输入样例
6
-20 11 -4 13 -5 -2
输出样例
20
bi是i到n区间的最大子段和(i ~ n,i-1~ n,1~n,共i个子段)
/*计算最大值*/
#include<bits/stdc++.h>
#define NUM 1000
using namespace std;
int x[NUM]; /*序列*/
int sum; /*最大子段和*/
int y; /*i到n的最大子段和*/
int add(int n){
for(int i=n;i>0;i--){
if(y>0){
y+=x[i];
}else{
y=x[i];
}
if(y>sum){
sum=y;
}
}
return sum;
}
int main() {
//freopen("in.txt","r",stdin);
int n;
cin>>n;
for(int i=0;i<n;i++){
cin>>x[i];
}
cout<<add(n);
//fclose(stdin);
return 0;
}
/***********************************/
/*计算子段和的最优解*/
/*
输入:
8
1 -3 7 8 -4 12 -10 6
输出:
23
3->6
*/
#include<bits/stdc++.h>
#define NUM 1000
using namespace std;
int x[NUM]; /*序列*/
int add(int n,int &p,int &q) {
int sum; /*最大子段和*/
int y; /*i到n的最大子段和*/
int begin=0;
for(int i=n; i>=1; i--) {
if(y>0) {
y+=x[i];
} else {
y=x[i];
begin=i+1;
}
if(y>sum) {
sum=y;
p=i+1;
q=begin;
}
}
return sum;
}
int main() {
//freopen("in.txt","r",stdin);
int n,p,q;
cin>>n;
for(int i=0; i<n; i++) {
cin>>x[i];
}
cout<<add(n,p,q)<<endl;
cout<<p<<"->"<<q<<endl;
//fclose(stdin);
return 0;
}
3.最长单调递增子序列
输入
8
65 158 170 155 239 300 207 389
输出
6
#include<bits/stdc++.h>
#define NUM 1000
using namespace std;
int x[NUM]; /*序列*/
int y[NUM]; /*记录以a[i]为结尾的元素的最长递增子序列的长度*/
int add(int n) {
int m=0;/*最终结果*/
y[1]=1;
for(int i=2;i<=n;i++) {
int k=0;
for(int j=1;j<i;j++){
if(x[j]<=x[i]&&k<y[j]){
k=y[j];
}
}
y[i]=k+1;
if(m<y[i]){
m=y[i];
}
}
return m;
}
int main() {
//freopen("in.txt","r",stdin);
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>x[i];
}
cout<<add(n);
//fclose(stdin);
return 0;
}
4. 0-1背包问题
给定一个物品集合s={1,2,3,…,n},物品i的重量是wi,其价值是vi,背包的容量为W,即最大载重量不超过W。在限定的总重量W内,我们如何选择物品,才能使得物品的总价值最大。
输入样例
5 4
2 12
1 10
3 20
2 15
输出样例
37
分析:
阶段:
i~n ,依次处理每一件物品
状态:
背包的容量:0~m
决策:
在第i阶段,在背包容量是v(0~m之间) 的情况下,如何处理第i 件物品,才能使装入背包中的物品最大。
f[i][v]表示前i件物品(部分或全部)放入一个容量为v的背包可以获得的最大价值。处理方案:
在w[i]>v的情况下,不装入;
f[i][v]=f[i-1][v]
否则,根据
max{f[i-1][v],f[i-1][v-w[i]]+c[i]}
进行决策
状态转移方程便是:
f[i][v]=max{f[i-1][v],f[i-1][v-w[i]]+c[i]}。
#include<bits/stdc++.h>
#define N 1000
using namespace std;
int w[N],v[N],f[N][N];
int main() {
int c,n;
//freopen("in.txt","r",stdin);
cin>>c>>n;
for(int i=1; i<=n; i++) {
cin>>w[i]>>v[i];
}
for(int i=1;i<=n;i++){
for(int j=c;j>0;j--){
if(w[i]<=j){
f[i][j]=max(f[i-1][j],f[i-1][j-w[i]]+v[i]);
}else{
f[i][j]=f[i-1][j];
}
}
}
cout<<f[n][c]<<endl;
//fclose(stdin);
return 0;
/*优化空间复杂度*/
#include<bits/stdc++.h>
#define N 1000
using namespace std;
int w[N],v[N],f[N];
int main() {
int c,n;
//freopen("in.txt","r",stdin);
cin>>c>>n;
for(int i=1; i<=n; i++) {
cin>>w[i]>>v[i];
}
for(int i=1;i<=n;i++){
for(int j=c;j>=w[i];j--){
if(f[j-w[i]]+v[i]>f[j]){
f[j]=f[j-w[i]]+v[i];
}
}
}
cout<<f[c]<<endl;
//fclose(stdin);
return 0;
}
5.最长公共子序列
描述
若给定序列X={x1,x2,…,xm},则另一序列Z={z1,z2,…,zk},是X的子序列是指存在一个严格递增下标序列{i1,i2,…,ik}使得对于所有j=1,2,…,k有:zj=xij。
例如,序列Z={B,C,D,B}是序列X={A,B,C,B,D,A,B}的子序列。
给定2个序列X和Y,当另一序列Z既是X的子序列又是Y的子序列时,称Z是序列X和Y的公共子序列。
给定2个序列X={x1,x2,…,xm}和Y={y1,y2,…,yn},找出X和Y的最长公共子序列。
输入
三行.第一行m和n,分别表示两个子序列的长度(符号的个数)
接下来两行,分别表示X和Y
输出
最长公共子序列的长度
样例输入
7 6
ABCBDAB
BDCABA
样例输出
4
#include<bits/stdc++.h>
#define N 1000
using namespace std;
int l[N][N];
int max(int a,int b){
if(a>=b) return a;
else return b;
}
int LCS(int m,int n,char x[],char y[]){
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
if(x[i]==y[j]){
l[i][j]=l[i-1][j-1]+1;
}else{
l[i][j]=max(l[i-1][j],l[i][j-1]);
}
}
}
return l[m][n];
}
int main() {
//freopen("in.txt","r",stdin);
char x[N],y[N];
int m,n;
cin>>m>>n;
for(int i=1;i<=m;i++) cin>>x[i];
for(int j=1;j<=n;j++) cin>>y[j];
cout<<LCS(m,n,x,y)<<endl;
//fclose(stdin);
return 0;
}