高级数据结构04动态规划
文章目录
- 高级数据结构04动态规划
- 1.整体结构
- 2.实际应用
高级数据结构04动态规划
1.整体结构
2.实际应用
// 动态规划.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include "pch.h"
#include <iostream>
#include <string>
#include <cmath>
#include <algorithm>
using namespace std;
/*
穷举法:O(2^n) => 剪枝操作
0-1背包
有一个物品,它们的重量是:
wn = {w1,w2...wn}
价值是:
vn = {v1,v2...vn}
现在有一个背包,其容量是C,问怎么装入物品,使背包的价值最大化???
X0-Xm Y0-Yn
dp[m][n]:
i-n j:背包的容量
dp[i][j] : 可选择的物品是i...n,背包容量是j的时候,背包装入物品的最大价值
当i == n的时候,dp[n][j] =
wn > j : dp[n][j] = 0
wn <= j: dp[n][j] = vn
当i != n的时候 i..n
wi > j : dp[i][j] = dp[i+1][j]
wi <=j : dp[i][j] = max{dp[i+1][j], dp[i+1][j-wi]+vi}
dp[i][j]:0...i个物品的最优价值
0 == i
w0 > j : dp[0][j] = 0
w0 <= j: dp[0][j] = v0
0 != i
wi > j : dp[i][j] = dp[i-1][j]
wi <=j : dp[i][j] = max{dp[i-1][j], dp[i-1][j-wi]+vi}
*/
int w[] = { 8,6,5,9,7 };
int v[] = { 7,9,6,3,8 };
const int C = 18;
const int SIZE = sizeof(w) / sizeof(w[0]);
int dp[SIZE][C + 1];
void backstrace()
{
int bestv = 0;
int bestx[SIZE] = { 0 };
int c = C;
for (int i = 0; i < SIZE-1; ++i)
{
if (dp[i][c] != dp[i + 1][c]) // i被选择了
{
bestv += v[i];
c -= w[i];
bestx[i] = 1;
}
}
if (dp[SIZE - 1][c] > 0)
{
bestv += v[SIZE - 1];
bestx[SIZE - 1] = 1;
}
cout << "max value:" << bestv << endl;
for_each(bestx, bestx + SIZE, [](int a) {
cout << a << " ";
});
}
int main()
{
int n = SIZE - 1;
for (int j = 1; j <= C; ++j) // j
{
if (w[n] > j)
{
dp[n][j] = 0;
}
else
{
dp[n][j] = v[n];
}
}
// C*O(n) O(2^n)
for (int i = n - 1; i >= 0; --i) // 循环物品
{
for (int j = 1; j <= C; ++j) // 循环背包容量
{
if (w[i] > j) // 6 7 5
{
dp[i][j] = dp[i + 1][j];
}
else
{
dp[i][j] = max(dp[i + 1][j], dp[i + 1][j - w[i]] + v[i]);
}
}
}
for (int i = 0; i < SIZE; ++i)
{
for_each(dp[i], dp[i] + C + 1, [](int a) {
cout << a << " ";
});
cout << endl;
}
backstrace();
return 0;
}
/*
最大子段和的问题
int ar[] = { -2,11,-4,13,-5,-2 };
dp(i):以第i个元素结尾的最大字段和的长度
dp(0):0
dp(1):dp(0)+ar[1] = 11
dp(2):-4 + dp(1) = 7
dp(3):dp(2)+13 = 20
dp(i) = dp(i-1)+ar[i] < 0 0
*/
void backstace(int ar[], int dp[], int end, int max)
{
}
int main05()
{
int max = 0;
int ar[] = { -2,11,-4,13,-5,-2 };
// 0 11 7 20
const int c = sizeof(ar) / sizeof(ar[0]);
int dp[c] = { 0 };
dp[0] = ar[0];
if (dp[0] < 0)
{
dp[0] = 0;
}
for (int i = 1; i < c; ++i) // O(n)
{
dp[i] = dp[i - 1] + ar[i];
if (dp[i] < 0)
{
dp[i] = 0;
}
if (dp[i] > max)
max = dp[i];
}
cout << max << endl;
for_each(dp, dp + c, [](int a) {cout << a << " "; });
backstace(ar, dp, c-1, max);
return 0;
}
/*
求LIS问题,最长非降子序列的长度
int ar[]={8,3,4,7,2,9};
dp(i): 以第i个元素结尾的LIS的长度
dp(0) = 1 // 8
dp(1) = 1 // 3 8>3
dp(2) = 2 // 3 4
dp(3) = 3 // 3, 4, 7
dp(i) = max{dp(j)}+1 j<i&&ar[i]>=ar[j]
*/
int main04()
{
int max = 0;
int ar[] = { 8,3,4,7,2,9 };
int dp[6] = { 0 };
for (int i = 0; i < 6; ++i)
{
dp[i] = 1;
for (int j = 0; j < i; ++j)
{
if (ar[i] >= ar[j] && dp[j] + 1 > dp[i])
{
dp[i] = dp[j] + 1;
}
}
if (max < dp[i])
{
max = dp[i];
}
}
cout << "max lis:" << max << endl;
return 0;
}
/*
状态 - 状态转移方程
硬币选择的问题:
1,3,5面额的硬币,现在给一个价值,问组成该价值需要的
最少的硬币的数量是多少?
dp(i) : i价值所需要的硬币的最少数量
int c = 11; 1 10 5 5
dp(0) = 0
dp(1) = dp(1-1)+1 = dp(0) + 1 = 1
dp(2) = dp(2-1)+1 = dp(1) + 1 = 1 + 1 = 2
dp(3):
dp(3-1)+1 = dp(2)+1 = 2 + 1 = 3
dp(3-3)+1 = dp(0)+1 = 0 + 1 = 1
dp(5):
dp(5-1)+1 = dp(4)+1
dp(5-3)+1 = dp(2)+1
dp(5-5)+1 = dp(0)+1
dp(i) = min{dp(i-1)+1,dp(i-3)+1,dp(i-5)+1}
dp(i) = min{dp(i-vj)+1} i表示价值 vj表示硬币的面额 i>=vj
dp(11):
dp(11-1)+1 = dp(10)+1
dp(11-3)+1 = dp(8)+1
*/
int main03()
{
int ar[] = { 1,3,5 };
const int c = 11;
int dp[c + 1] = {0}; // dp[11]
for (int i = 1; i <= c; ++i)
{
dp[i] = i;
for (int j = 0; j < sizeof(ar) / sizeof(ar[0]); ++j)
{
if (i >= ar[j] && dp[i - ar[j]] + 1 < dp[i])
{
dp[i] = dp[i - ar[j]] + 1;
}
}
}
cout << "价值11需要的最少的硬币数量是:" << dp[c] << endl;
for_each(dp, dp + c + 1, [](int a) {cout << a << " "; });
return 0;
}
/*
分治算法
规模N
N/2 N/2
N/4 N/4 N/4 N/4
LCS:求解两个序列的最长公共子序列(最长子串)的长度问题
X = {X1,X2...Xn-1,Xm} hello world hello world hello worl
Y = {Y1,Y2...Yn-1,Yn} hecdle hecdl
{X1,X2...Xn-1,Xn}和{Y1,Y2...Yn-1}
{X1,X2...Xn-1}和{Y1,Y2...Yn-1,Yn}
求X和Y序列的最长公共子序列 分治算法
当Xm == Yn的时候 n和n-1
LCS(Xm,Yn) = LCS(Xm-1,Yn-1) + 1
当Xm != Yn的时候
LCS(Xm,Yn) = max{LCS(Xm,Yn-1),LCS(Xm-1, Yn)}
当X1 == Y1
LCS(Xn,Yn) = LCS(X2-Xn,Y2-Yn) + 1
*/
#if 0
int mycount = 0;
const int XSIZE = 10;
const int YSIZE = 6;
/*
动态规划算法的核心:找出问题的“状态”和“状态转移方程”
dp[m][n] : 表示X0-Xm,Y0-Yn的LCS的长度
当Xm == Yn
dp[m][n] = dp[m-1][n-1]+1
当Xm != Yn
if(dp[m-1][n] > dp[m][n-1])
{
dp[m][n] = dp[m-1][n];
}
else
{
dp[m][n] = dp[m][n-1];
}
*/
int dp[XSIZE][YSIZE];
int path[XSIZE][YSIZE];
int LCS(string x, string y, int m, int n)
{
if (m < 0 || n < 0)
return 0;
if (dp[m][n] >= 0)
{
return dp[m][n]; // X0-Xm Y0-Yn
}
mycount++;
if (x[m] == y[n])
{
dp[m][n] = LCS(x, y, m - 1, n - 1) + 1;
path[m][n] = 1;
}
else // x[m] != y[n]
{
int size1 = LCS(x, y, m - 1, n); // X1...Xm-1 Y1...Yn
int size2 = LCS(x, y, m, n - 1); // X1...Xm Y1...Yn-1
if (size1 > size2)
{
dp[m][n] = LCS(x, y, m - 1, n);// 上面
path[m][n] = 2;
}
else
{
dp[m][n] = LCS(x, y, m, n - 1); // 左边
path[m][n] = 3;
}
}
return dp[m][n];
}
#endif
#if 0
int dp[XSIZE + 1][YSIZE + 1] = {0};
int NON_LCS(string x, string y, int m, int n)
{
for (int i = 1; i <= m+1; ++i)
{
for (int j = 1; j <= n+1; ++j)
{
if (x[i-1] == x[j-1])
{
dp[i][j] = dp[i-1][j-1] + 1;
}
else
{
if (dp[i-1][j] > dp[i][j-1])
{
dp[i][j] = dp[i - 1][j];
}
else
{
dp[i][j] = dp[i][j - 1];
}
}
}
}
return dp[XSIZE][YSIZE];
}
#endif
#if 0
void backstrace(string x, int m, int n)
{
if (m < 0 || n < 0)
return;
if (path[m][n] == 1)
{
backstrace(x, m - 1, n - 1);
cout << x[m] << " ";
}
else
{
if (path[m][n] == 2)
{
backstrace(x, m - 1, n);
}
else
{
backstrace(x, m, n - 1);
}
}
}
#endif
#if 0
int main01()
{
string X = "helloworld";
string Y = "hecdld"; // he ld
#if 0
for (int i = 0; i < XSIZE; ++i)
{
fill(dp[i], dp[i] + YSIZE, -1);
}
#endif
//int size = LCS(X, Y, X.length()-1, Y.length()-1);
int size = NON_LCS(X, Y, X.length() - 1, Y.length() - 1);
cout << "size:" << size << endl;
cout << "mycount:" << mycount << endl;
#if 1
for (int i = 0; i < XSIZE; ++i)
{
for_each(dp[i], dp[i] + YSIZE, [](int a) {
cout << a << " ";
});
cout << endl;
}
cout << endl;
#endif
// 输出最长的LCS的字符
//backstrace(X, X.length() - 1, Y.length() - 1);
return 0;
}
#endif
原文地址:https://blog.csdn.net/sunshinecandy/article/details/146560495
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.kler.cn/a/612343.html 如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.kler.cn/a/612343.html 如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!