线性DP的知识点

本篇是写给自己的复习笔记,所以写得很潦草…ε=ε=ε=┏(゜ロ゜;)┛

  • 最长公共子序列
  • 最大连续子序列
  • 上升子序列的最大和
  • 最小完全背包

**

最长公共子序列

**
题目:Common Subsequence!
在这里插入图片描述
INPUT

abcfbc abfcab
programming contest 
abcd mnp

OUTPUT

4
2
0

题目大意:
给出字符串,求 各自 子串中 有序相同的最大个数(注意不用连续)(而且两个字符串长度并不一定相等)
例如:
abcfbc 和 abfcab
符合的子串为:abcb,所以答案是4。

解法:
例如两字符串为:
bdcaba 和 abcbdab
构造二者的二维矩阵
在这里插入图片描述
(老图了)
真的只能自己悟其中的妙,可以看出它其实把每两个字母都进行有序配对在max取最大
ε=ε=ε=┏(゜ロ゜;)┛

得出方程(记公式吧)
在这里插入图片描述
在这里插入图片描述
AC代码

#include<bits/stdc++.h>
using namespace std;
int dp[1005][1005];
int main()
{
	string a,b;
	while(cin>>a>>b)
	{
		memset(dp,0,sizeof(dp));
		int lena = a.length();
		int lenb = b.length();
		for(int i = 0;i<=lena;i++)
			for(int j = 0;j<=lenb;j++)
			{
				if(i == 0 || j == 0)
				{
					dp[i][j] = 0;
					continue;
				}
				if(a[i - 1] == b[j - 1])
					dp[i][j] = dp[i - 1][j - 1] + 1;
				else
					dp[i][j] = max(dp[i - 1][j] , dp[i][j - 1]);
			}
		cout<<dp[lena][lenb]<<endl;
	}
	return 0;
}

**

最大连续子序列

**

在这里插入图片描述
INPUT

6
-2 11 -4 13 -5 -2
10
-10 1 2 3 4 -5 -23 3 7 -21
6
5 -8 3 2 5 0
1
10
3
-1 -5 -2
3
-1 0 -2
0

OUTPUT

20 11 13
10 1 4
10 3 5
10 10 10
0 -1 -2
0 0 0

思路:
详情见dalao的csdn
开一个cur(表示已知最大值),一个hismax(存目前前缀和)
当hismax比cur大的时候赋值给cur
小于的时候就不赋值
如果hismax甚至小到小于0,就直接等于0,相当于都不取,
下面模拟一遍
-2 11 -4 13 -5 -2

cur和hismax为当前的值

curhismax
-200
111111
-4117
132020
-52015
-22013

AC代码
下面是加上对坐标的记录,了解了如何动态规划(去大佬的博客)存储应该同时存储坐标难度不大。
详情见代码吧

#include <iostream>
#include <cstring>
using namespace std;

const int maxn = 10005;
int res[maxn] = {0};
int num[maxn] = {0};
int cur(0), hismax(0), op(0), ed(0), opi(-1);

int main()
{
	int n(0);
	while (scanf("%d", &n))
	{
		if (n == 0)
			break;

		for (int i(0); i < n; ++i)
			scanf("%d", &num[i]);

		cur = 0;
		opi = -1;

		hismax = num[0];
		op = num[0];
		ed = num[n - 1];

		for (int i(0); i < n; ++i)
		{
			if (cur > 0)
				cur += num[i];
			else
			{
				cur = num[i];
				opi = i;
			}
			if (cur > hismax)
			{
				hismax = cur;
				ed = num[i];
				op = num[opi];
			}
		}
		if (hismax < 0)
			hismax = 0;
		printf("%d %d %d\n", hismax, op, ed);
	}
	return 0;
}


**

上升子序列的最大和

**
题目:Super Jumping! Jumping! Jumping!
在这里插入图片描述
在这里插入图片描述
INPUT

3 1 3 2
4 1 2 3 4
4 3 3 2 1
0

OUTPUT

4
10
3

做法:
将每个峰值(当前坐标的下一个是下降的)记录为dp[i],每加入一个数就往回搜索比对出最大的sum,最后更新下新的dp就好

#include<bits/stdc++.h>
using namespace std;
int e[1005];
int dp[1005];
int n;
int main()
{
	while(cin>>n && n)
	{
		for(int i = 1;i<=n;i++)	cin>>e[i];
		e[0] = 0;
		int maxx = -1;
		for(int i = 1;i<=n;i++)
		{
			int q = -1;
			for(int j = 0;j<i;j++)
				if(e[i] > e[j])
					q = max(q,dp[j]);
			dp[i] = q + e[i];
			maxx = max(maxx,dp[i]);
		}
		cout<<maxx<<endl;
	}
	return 0;
}

题目:Piggy-Bank
在这里插入图片描述
在这里插入图片描述

INPUT

3
10 110
2
1 1
30 50
10 110
2
1 1
50 30
1 6
2
10 3
20 4

OUTPUT

The minimum amount of money in the piggy-bank is 60.
The minimum amount of money in the piggy-bank is 100.
This is impossible.

反向背包操作,求最小值就好
将for循环倒置以及max改成min就好

AC代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll T,n,m,num,a,b;
ll v[2005];
ll cnt[2005];
ll dp[20005];
int main()
{
	cin>>T;
	while(T--)
	{
		memset(dp,0x3f,sizeof(dp));
		dp[0] = 0;
		cin>>a>>b>>m;
		n = abs(b - a);
		for(ll i = 1;i<=m;i++)	{cin>>v[i];cin>>cnt[i];}
		for(ll i = 1;i<=m;i++)
			for(ll j = cnt[i];j <= n;j++)
				dp[j] = min(dp[j],dp[j - cnt[i]] + v[i]);
		if(dp[n] >= 0x3f3f3f3f)
		    printf("This is impossible.\n");
		else
			printf("The minimum amount of money in the piggy-bank is %d.\n", dp[n]);
	}
	return 0;
}

如有问题敬请指正哈

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值