本篇是写给自己的复习笔记,所以写得很潦草…ε=ε=ε=┏(゜ロ゜;)┛
- 最长公共子序列
- 最大连续子序列
- 上升子序列的最大和
- 最小完全背包
**
最长公共子序列
**
题目: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为当前的值
cur | hismax | |
---|---|---|
-2 | 0 | 0 |
11 | 11 | 11 |
-4 | 11 | 7 |
13 | 20 | 20 |
-5 | 20 | 15 |
-2 | 20 | 13 |
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;
}
如有问题敬请指正哈