11.1~11.6 动态规划
11.1~11.6 动态规划
11.2 最大连续子序列
http://codeup.hustoj.com/contest.php?cid=100000626

题目解析
因为要输出序列的首尾元素,所以定义了结构体
代码
#include <cstdio>
#include <cstring>
#define maxn 10005
struct node {
int s, t; //对应a中的起点终点值
int sum;
} dp[maxn];// dp[i]表示以i结尾的最大连续子序列和
int main() {
int n;
int a[maxn];
while (scanf("%d", &n) && n) {
memset(dp, 0, sizeof(dp));
for (int i = 0; i < n; i++) {
scanf("%d", &a[i]);
}
dp[0].s = dp[0].t = dp[0].sum = a[0];
for (int i = 1; i < n; i++) {
if (a[i] >= dp[i - 1].sum + a[i]) {
dp[i].s = dp[i].t = dp[i].sum = a[i];
} else {
dp[i].s = dp[i - 1].s;
dp[i].t = a[i];
dp[i].sum = dp[i - 1].sum + a[i];
}
}
int index = 0;
for (int i = 1; i < n; i++) {
if (dp[i].sum > dp[index].sum) {
index = i;
}
}
if (dp[index].sum < 0) printf("0 %d %d\n", a[0], a[n - 1]);
else printf("%d %d %d\n", dp[index].sum, dp[index].s, dp[index].t);
}
return 0;
}
11.3 最长上升(不下降)子序列 LIS
http://codeup.hustoj.com/contest.php?cid=100000627

题目解析
emmmmm没事哈好说的,纯粹模板题
代码
#include <cstdio>
#include <algorithm>
using namespace std;
#define maxn 1005
int main() {
int n;
int a[maxn], dp[maxn]; //dp[i]表示以a[i]结尾的最长上升子序列的长度
scanf("%d", &n);
for (int i = 0; i < n; i++) {
scanf("%d", &a[i]);
}
int ans = -1;
for (int i = 0; i < n; i++) {
dp[i] = 1; //初始化
for (int j = 0; j < i; j++) {
if (a[j] <= a[i]) {
dp[i] = max(dp[i], 1 + dp[j]);
}
}
if (dp[i] > ans) ans = dp[i];
}
printf("%d\n", ans);
return 0;
}
11.4 最长公共子序列
http://codeup.hustoj.com/contest.php?cid=100000628

题目解析
递归边界若是dp[i][0]=dp[0][j]=0,则字符串下标1开始。
此处用string记录字符串,故字符串下标从0开始,故用
dp[i + 1][j + 1]=dp[i][j] + 1(若a[i] = b[j])
dp[i + 1][j + 1] = max(dp[i][j + 1], dp[i + 1][j]);(若a[i] != b[j])
代码
#include <cstdio>
#include <iostream>
#include <string>
#include <algorithm>
#define maxn 105
using namespace std;
int main() {
string a, b;
int dp[maxn][maxn]; //dp[i+1][j+1]表示a[i]和b[j]之前的最长公共子序列长度
while (cin >> a >> b) {
for (int i = 0; i <= a.length(); i++) {
dp[i][0] = 0;
}
for (int i = 0; i <= b.length(); i++) {
dp[0][i] = 0;
}
for (int i = 0; i < a.length(); i++) {
for (int j = 0; j < b.length(); j++) {
if (a[i] == b[j]) dp[i + 1][j + 1] = dp[i][j] + 1;
else dp[i + 1][j + 1] = max(dp[i][j + 1], dp[i + 1][j]);
}
}
printf("%d\n",dp[a.length()][b.length()]);
}
return 0;
}
11.5 最长回文字符串
http://codeup.hustoj.com/contest.php?cid=100000629

题目解析
将输入的字符串读入buf,将buf中的字母及数字存储到要进行回文比较的字符串s中(字母都转化成小写),为了最后能输对应的buf,用 p 数组记录 s 下标到 buf 下标的映射。
回文比较采用枚举回文串“中间”的i,然后不断向外扩张(书中的方法),此处要记录最长回文串长度以及起点在字符串s中的下标(都记录第一个>max_len的值,因为题目中要求若有多个相同长度回文串,输出起始位置最靠左的,也就是 i 最小的)
代码
#include <cstdio>
#include <cstring>
#include <algorithm>
#define maxn 5005
char buf[maxn], s[maxn];
int p[maxn]; //s下标到buf的映射
bool dp[maxn][maxn] = {false}; //dp[i][j]——s数组中下标i到j的字符串是否为回文字符串
int main() {
gets(buf);
int s_len = 0;
// 将buf中的字母变小写和数字一起放入s,建立s下标到buf的映射p
for (int i = 0; i < strlen(buf); i++) {
if (isalpha(buf[i])) {
s[s_len] = tolower(buf[i]);
p[s_len] = i;
s_len++;
} else if (isdigit(buf[i])) {
s[s_len] = buf[i];
p[s_len] = i;
s_len++;
}
}
int max_len = 1, start = 0;
for (int i = 0; i < s_len; i++) {
dp[i][i] = true;
if (i < s_len - 1 && s[i] == s[i + 1]) {
dp[i][i + 1] = true;
if (max_len < 2) {
max_len = 2;
start = i;
}
}
}
for (int L = 3; L <= s_len; L++) {
for (int i = 0; i + L - 1 < s_len; i++) {
int j = i + L - 1;
if (s[i] == s[j] && dp[i + 1][j - 1]) {
dp[i][j] = true;
if (max_len < L) {
max_len = L;
start = i;
}
}
}
}
for (int i = p[start]; i <= p[start + max_len - 1]; i++) {
printf("%c", buf[i]);
}
printf("\n");
return 0;
}
10.7 关键路径
http://codeup.hustoj.com/contest.php?cid=100000627

题目解析
这道题用了dp做,书p439页有讲解
PS:个人觉得这里输入给出的各顶点abcde没啥用,但有可能不是按照26个英文字母顺序给出的顶点
(我默认顶点是顺序给出的AC了)
用拓扑排序的代码可参考:https://blog.csdn.net/morizunzhu/article/details/96652800
代码
#include <cstdio>
#include <algorithm>
#include <iostream>
using namespace std;
#define maxn 20
#define INF 0x3fffffff
int n, G[maxn][maxn]; //存图
int dp[maxn]; //dp[i]表示以i为起点的能得到的最长路径长度
int choose[maxn];
int DP(int i) {
if (dp[i] > 0) return dp[i];
for (int j = 0; j < n; j++) {
if (G[i][j] != INF) {
int temp = DP(j) + G[i][j];
if (temp > dp[i]) {
dp[i] = temp;
choose[i] = j;
}
}
}
return dp[i];
}
void printPath(int i) {
while (choose[i] != -1) {
printf("(%c,%c) ", i + 97, choose[i] + 97);
i = choose[i];
}
}
int main() {
int t, m, w;
char a, b;
scanf("%d", &t);
while (t--) {
fill(G[0], G[0] + maxn * maxn, INF);
fill(dp, dp + maxn, 0);
fill(choose, choose + maxn, -1);
scanf("%d%d", &n, &m);
char temp;
for (int i = 0; i < n; i++) {
cin >> temp;
}
for (int i = 0; i < m; i++) {
cin >> a >> b >> w;
G[a - 97][b - 97] = w;
}
int ans = 0, k,tt;
for (int i = 0; i < n; i++) {
tt = DP(i);
if (tt > ans) {
ans = tt;
k=i;
}
}
printPath(k);
printf("%d\n",ans);
}
return 0;
}
11.6 DAG 最长路 🌟
http://codeup.hustoj.com/contest.php?cid=100000630

题目解析
将此问题是典型 DAG 最长路问题,需将每个矩形都看作一个顶点,并将嵌套关系视为顶点之间的有向边,边权为1。
1️⃣ 构造DAG图,便于使用DP求DAG的最长路 ——将每个矩形变为一个顶点,根据矩形间是否能嵌套,判断两个顶点间是否有有向边
- 这里定义了结构体rect存储输入的矩形的宽,因为嵌套条件是a<c,b<d或者b<c,a<d,所以为了之后比较方便,统一将输入的更大的数作为长,另一个数作为宽
- 所有矩形数据输入完毕后,开始两两比较能否嵌套,默认每个矩形代表的顶点编号根据输入的顺序依次0~n-1,若能嵌套(r[i].l < r[j].l && r[i].w < r[j].w),则令顶点 i 与 j 之间有一条有向边( G[i][j] = 1)
2️⃣ 构造完 DAG图后,就是常规操作,使用DP计算最长路长度ans
3️⃣ 需注意的是,最后要输出的是能最多嵌套的矩形数目,⚠️ 所以输出ans+1
代码
#include <cstdio>
#include <algorithm>
#define maxn 1005
#define INF 0x3fffffff
using namespace std;
struct rect {
int l, w;
} r[maxn];
int n, G[maxn][maxn];
int dp[maxn];
int DP(int i) {
if (dp[i] > 0) return dp[i];
for (int j = 0; j < n; j++) {
if (G[i][j] != INF) {
dp[i] = max(dp[i], DP(j) + G[i][j]);
}
}
return dp[i];
}
int main() {
int t, a, b;
scanf("%d", &t);
while (t--) {
fill(G[0], G[0] + maxn * maxn, INF);
fill(dp, dp + maxn, 0);
scanf("%d", &n);
for (int i = 0; i < n; i++) {
scanf("%d%d", &a, &b);
if (a >= b) r[i].l = a, r[i].w = b;
else r[i].l = b, r[i].w = a;
}
for (int i = 0; i < n - 1; i++) {
for (int j = i + 1; j < n; j++) {
if (r[i].l < r[j].l && r[i].w < r[j].w) {
G[i][j] = 1;
}
}
}
int ans = 0, temp;
for (int i = 0; i < n; i++) {
temp = DP(i);
if (temp > ans) ans = temp;
}
printf("%d\n",ans+1);
}
return 0;
}
本文作者:Joey-Wang
本文链接:https://www.cnblogs.com/joey-wang/p/14541195.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步