DP
- 一个具有重叠子问题和最优子结构的问题,才可以使用动态规划
- 状态的无后效性:即已有的状态不会随着后面转变
避免重复计算
斐波那契数列
//斐波那契数列
//F0=1,F1=1,Fn=Fn-1+Fn-2
#include<algorithm>
using namespace std;
const int max_n = 100;
int f[max_n];
int Fib(int n)
{
if (f[n] != -1)
{
return f[n];
}
else
{
f[n] = Fib(n - 1) + Fib(n - 2);
}
return f[n];
}
int main()
{
fill(f, f + max_n, -1);
f[0] = 1;
f[1] = 0;
}
数塔
//树塔问题 第n层有n个数 求某一条路径上的最大值
//max[i]表示从i出发 某条路径和的最大值
#include<stdio.h>
const int max_n = 30;
int n,k;//假设有k层 n个结点
struct node
{
int w;
int left;
int right;
}Adj[max_n];
int max[max_n];
int main()
{
for (int i = n-1-k; i<n; i++)
{
max[i] = Adj[i].w;
}
for (int i = n - 2 - k; i>=0; i--)
{
if (max[Adj[i].left] > max[Adj[i].right])
{
max[i] = Adj[i].w + max[Adj[i].left];
}
else
{
max[i] = Adj[i].w + max[Adj[i].right];
}
}
}
最大连续子序列和
//最大连续子序列和
//给定一个数组 求出其最大连续子序列的和
const int max_n = 30;
int n;
int dp[max_n];//dp表示以i结尾的最大连续子序列的和
int w[max_n];
int max;
int main()
{
dp[0] = w[0];
max = dp[0];
for (int i = 1; i < n; i++)
{
if (w[i] > dp[i - 1] + w[i])
{
dp[i] = w[i];
}
else
{
dp[i] = w[i] + dp[i - 1];
}
if (dp[i] > max)
{
max = dp[i];
}
}
}
最长不减子序列
#include<iostream>
#include<stack>
using namespace std;
//在一个数组中 找到一组不下降的子序列
const int max_n = 100;
int main()
{
int n;
int dp[max_n];//记录以第i个元素结尾的序列最大长度
int max_pre[max_n];//记录第i个元素的前一个元素
int A[max_n];
int maxIndex = 0;//记录拥有最大不下降子序列的结尾
stack<int>s;
scanf("%d", &n);
for (int i = 0; i < n; i++)
{
scanf("%d", &A[i]);
}
fill(max_pre, max_pre + n, -1);
dp[0] = 1;
for (int i = 1; i < n; i++)
{
dp[i] = 1;
for (int j = 0; j <=i - 1; j++)
{
if (A[i] >= A[j] && dp[j] + 1 > dp[i])
{
dp[i] = dp[j] + 1;
max_pre[i] = j;
}
}
if (dp[maxIndex] < dp[i])
{
maxIndex = i;
}
}
int index = maxIndex;
while (max_pre[index]!=-1)
{
s.push(index);
index = max_pre[index];
}
s.push(index);
printf("%d\n",s.size());
while (!s.empty())
{
int f = s.top();
s.pop();
printf("%d ", A[f]);
}
}
最长公共子序列
题目描述
- 有两个字符串A和B,求一个字符串,这个字符串是A和B的公共子序列
代码
//最长公共子序列
#include<string>;
#include<algorithm>
#include<iostream>
#include<stack>
using namespace std;
//最长公共子序列
const int max_n = 300;
int alen, blen;
int dp[max_n][max_n];//表示Ai和Bj之间的最长公共子序列
int prex[max_n][max_n];
int prey[max_n][max_n];
string A, B;
stack<char> s;
int main()
{
for (int i = 0; i < max_n; i++)
{
for (int j = 0; j < max_n; j++)
{
prex[i][j] = -1;
prey[i][j] = -1;
}
}
cin >> A;
cin >> B;
alen = A.length();
blen = B.length();
dp[0][0] = A[0] != B[0] ? 0 : 1;
for (int j = 0; j < blen; j++)
{
dp[0][j]= A[0] != B[j] ? 0 : 1;
}
int res = 0;
int x = 0, y = 0;
for (int j = 0; j < alen; j++)
{
dp[j][0] = A[j] != B[0] ? 0 : 1;
}
for (int i = 1; i < alen; i++)
{
for (int j = 1; j < blen; j++)
{
if (A[i] == B[j])
{
dp[i][j] = dp[i - 1][j - 1] + 1;
prex[i][j] = i - 1;
prey[i][j] = j - 1;
}
else
{
if (dp[i - 1][j] > dp[i][j - 1])
{
dp[i][j] = dp[i - 1][j];
prex[i][j] = i - 1;
prex[i][j] = j;
}
else
{
dp[i][j] = dp[i][j-1];
prex[i][j] = i;
prex[i][j] = j-1;
}
}
if (res < dp[i][j])
{
res = dp[i][j];
x = i;
y = j;
}
}
}
printf("%d\n",res);
while (x!=-1)
{
s.push(A[x]);
int a = x, b = y;
x = prex[a][b];
y = prey[a][b];
}
for (int i = 0; i < res; i++)
{
int v = s.top();
s.pop();
printf("%c ", v);
}
}
最长回文子串
//最长回文子串
#include<iostream>
using namespace std;
const int max_n = 300;
int n;
int maxL=1, maxX=0, maxY=0;
bool dp[max_n][max_n];
string s;
int main()
{
cin >> s;
n = s.length();
//初始化
for (int i = 0; i < n; i++)
{
dp[i][i] = true;
}
for (int i = 0; i < n-1; i++)
{
dp[i][i + 1] = s[i] == s[i + 1];
}
for (int L = 3; L <= n; L++)
{
for (int i = 0; i < n+1-L; i++)
{
int end = i + L - 1;
dp[i][end] = false;
if (s[i] == s[end])
dp[i][end] = dp[i + 1][end - 1];
}
}
for (int i = 0; i < n; i++)
{
for (int j = i; j < n; j++)
{
if (dp[i][j])
{
int tL = j - i + 1;
if (tL > maxL)
{
maxL = tL;
maxX = i;
maxY = j;
}
}
}
}
printf("%d\n", maxL);
for (int i = maxX; i <= maxY; i++)
{
printf("%c", s[i]);
}
}
DAG最长路
//DAG最长路
#include<iostream>
#include<algorithm>
using namespace std;
const int max_n = 300;
const int INF = 0x3fffffff;
int n;
int G[max_n][max_n];
bool dp[max_n];//表示从i出发的最长路径
int nextNode[max_n];//记录i的后继结点
int DP(int x)
{
if (dp[x] != 0)return dp[x];
for (int i = 0; i < n; i++)
{
if (G[x][i]!=INF)
{
int temp = DP(i) + G[x][i];
if (temp > dp[x])
{
dp[x] = temp;
nextNode[x] = i;
}
}
}
return dp[x];
}
int main()
{
fill(dp,dp+n,0);
fill(nextNode, nextNode + n, -1);
int maxIndex = 0;
for (int i = 0; i < n; i++)
{
if (dp[i] > dp[maxIndex])
{
maxIndex = i;
}
}
printf("%d", dp[maxIndex]);
int index = maxIndex;
while (nextNode[index] != -1)
{
printf("%d ", index);
index = nextNode[index];
}
}