11.4最长公共子序列(LCS)
问题 A: 最长公共子序列
问题描述:给你一个序列X和另一个序列Z,当Z中的所有元素都在X中存在,并且在X中的下标顺序是严格递增的,那么就把Z叫做X的子序列。
例如:Z=<a,b,f,c>是序列X=<a,b,c,f,b,c>的一个子序列,Z中的元素在X中的下标序列为<1,2,4,6>。
现给你两个序列X和Y,请问它们的最长公共子序列的长度是多少?
- 输入
输入包含多组测试数据。每组输入占一行,为两个字符串,由若干个空格分隔。每个字符串的长度不超过100。
- 输出
对于每组输入,输出两个字符串的最长公共子序列的长度。
- 样例输入
abcfbc abfcab
programming contest
abcd mnp
- 样例输出
4
2
0
codeup会报编译错误,注意要加上cstring的头文件,注意下标是从1开始的,所以要
scanf("%s %s",A+1,B+1)
我现在才知道可以查看codeup的编译信息,orz,之前的编译错误都没管,感觉错过了一个亿。
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 110;
int dp[maxn][maxn];
char A[maxn],B[maxn];
int main() {
while (scanf("%s %s",A+1,B+1)!=EOF)
{
int lenA = strlen(A + 1);
int lenB = strlen(B + 1);
for (int i = 0; i <= lenA; i++)
{
dp[i][0] = 0;
}
for (int j = 0; j <= lenB; j++)
{
dp[0][j] = 0;
}
for (int i = 1; i <= lenA; i++)
{
for (int j = 1; j <= lenB; j++)
{
if (A[i] == B[j])
dp[i][j] = dp[i - 1][j - 1] + 1;
else
{
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
}
}
}
printf("%d\n",dp[lenA][lenB]);
}
return 0;
}
11.5最长回文子串
问题 A: 【字符串】最长回文子串
问题描述: 输入一个字符串,求出其中最长的回文子串。子串的含义是:在原串中连续出现的字符串片段。回文的含义是:正着看和倒着看相同。如abba和yyxyy。在判断回文时,应该忽略所有标点符号和空格,且忽略大小写,但输出应保持原样(在回文串的首部和尾部不要输出多余字符)。输入字符串长度不超过5000,且占据单独的一行。应该输出最长的回文串,如果有多个,输出起始位置最靠左的。
- 输入
一行字符串,字符串长度不超过5000。
- 输出
字符串中的最长回文子串。
- 样例输入
Confuciuss say:Madam,I'm Adam.
- 样例输出
Madam,I'm Adam
codeup又报编译错误了,怀疑它的库里面就没有gets函数呜呜
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
#include<cstdio>
#include<stdio.h>
using namespace std;
const int maxn = 5010;
int dp[maxn][maxn];
char S[maxn];
char S1[maxn];//统一化之后的字符串
int p[maxn];
int main() {
while (1)
{
gets_s(S);
int num = 0;
for (int i = 0; i < strlen(S); i++)
{
if (!isalpha(S[i]) && !isdigit(S[i]))//如果不是数字也不是字母
{
;
}
else if (isalpha(S[i]))//如果是字母
{
S1[num] = toupper(S[i]);
p[num++] = i;
}
else
{
S1[num] =S[i];
p[num++] = i;
}
}
int len = strlen(S1);
int ans = 1;
int max = 0;
int st=0, ed=0;
memset(dp, 0, sizeof(dp));
for (int i = 0; i < len; i++)
{
dp[i][i] = 1;
if (ans > max)
{
max = ans;
st = ed = p[i];
}
if(i < len - 1)
{
if (S1[i] == S1[i + 1])
{
dp[i][i + 1] = 1;
ans = 2;
if (ans > max)
{
max = ans;
st = p[i];
ed = p[i + 1];
}
}
}
}
for (int L = 3; L <= len; L++)
{
for (int i = 0; i + L - 1 < len; i++)
{
int j = i + L - 1;
if (S1[i] == S1[j] && dp[i + 1][j - 1] == 1)
{
dp[i][j] = 1;
ans = L;
if (ans > max)
{
max = ans;
st = p[i];
ed = p[j];
}
}
}
}
//至此,找到了最左最长回文在原字符串的起始位置和终止位置st,ed;
for (int i = st; i <= ed; i++)
printf("%c",S[i]);
printf("\n");
}
return 0;
}
11.6DAG最长路
DAG就是有向无环图
在前面关键路径那里用了四个数组ve,vl,e,l来更新,求解最长路径,下面用动态规划来求解,最长路和最短路原理一致
解决两个问题
11.6.1求整个DAG中的最长路径(不固定起点和终点)
可以用逆拓扑序列的方法来求解dp数组,
如果不用逆拓扑序列的方法,可以使用递归的方式;
递归需要用邻接矩阵来存储
11.6.2固定终点,求DAG中的最长路径
问题 A: 矩形嵌套
问题描述:有n个矩形,每个矩形可以用a,b来描述,表示长和宽。矩形X(a,b)可以嵌套在矩形Y(c,d)中当且仅当a<c,b<d或者b<c,a<d(相当于旋转X90度)。例如(1,5)可以嵌套在(6,2)内,但不能嵌套在(3,4)中。你的任务是选出尽可能多的矩形排成一行,使得除最后一个外,每一个矩形都可以嵌套在下一个矩形内。
- 输入
第一行是一个正正数N(0<N<10),表示测试数据组数,
每组测试数据的第一行是一个正正数n,表示该组测试数据中含有矩形的个数(n<=1000)
随后的n行,每行有两个数a,b(0<a,b<100),表示矩形的长和宽
- 输出
每组测试数据都输出一个数,表示最多符合条件的矩形数目,每组输出占一行
- 样例输入
1
10
1 2
2 4
5 8
6 10
7 9
3 1
5 8
12 10
9 7
2 2
- 样例输出
5
这题要注意build函数是怎么构造邻接矩阵的
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<stdio.h>
#include<vector>
using namespace std;
const int maxn = 1010;
int N, n;
int G[maxn][maxn];
int dp[maxn];
int choice[maxn];
struct node {
int x, y;
node(int x = 0, int y = 0) :x(x), y(y) {}
};
vector<node> vec;
void build()
{
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
{
if (i != j)
{
int a, b, c, d;
a = vec[i].x, b = vec[i].y;
c = vec[j].x, d = vec[j].y;
if (a < c && b < d || b < c && a < d) G[i][j] = 1;
}
}
}
int DP(int i)
{
if (dp[i] > 0) return dp[i];
dp[i] = 1;
for (int j = 0; j < n; j++)
{
if (G[i][j])
{
int temp = DP(j) + G[i][j];
if (temp > dp[i])
{
dp[i] = temp;
choice[i] = j;
}
}
}
return dp[i];
}
void printPath(int i)
{
printf("%d",i);
while (choice[i] != -1)
{
i = choice[i];
printf("->%d",i);
}
printf("\n");
}
int main() {
scanf("%d", &N);
for (int i = 1; i <= N; i++)
{
scanf("%d", &n);
for (int j = 0; j < n; j++)
{
int x, y;
scanf("%d%d", &x, &y);
vec.push_back(node(x, y));
}
fill(G[0], G[0] + maxn * maxn, 0);
fill(dp, dp + maxn, 0);
fill(choice, choice + maxn, -1);
build();
for (int j = 0; j < n; j++)
{
dp[j]=DP(j);
}
int k = 0;
for (int j = 1; j < n; j++)
{
if (dp[j] > dp[k])
k = j;
}
printf("%d\n", dp[k]);
//printPath(k);
vec.clear();
}
return 0;
}