当前位置: 首页 > article >正文

高级数据结构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

相关文章:

  • Quarkus云原生服务开发详解
  • 《向量数据库指南》——解密DeepSearcher:推动AI智能报告生成的新范式
  • leetcode543.二叉树的直径
  • HarmonyOS-ArkUI Grip组件
  • QTcpSocket(客户端实现)多线程连接慢问题
  • MyBatis-Plus(Ⅲ)IService详解
  • python蓝桥杯刷题的重难点知识笔记
  • 【RHCE】LVS-NAT模式负载均衡实验
  • Flask接口开发--POST接口
  • 数据仓库 - 转转 - 一面凉经
  • 算力盒子VS边缘计算盒子
  • 脉冲编码器:精准定位与高效控制的科技先锋
  • 创建login.api.js步骤和方法
  • 【蓝桥杯】重点冲刺
  • ubuntu24.04.2 NVIDIA GeForce RTX 4060笔记本安装驱动
  • Milvus 与 Spring Boot 集成
  • SpringMVC 拦截器详解与实战
  • GAUSSDB 分布式存储机制深度解析
  • sortablejs el-table 树结构拖拽
  • PHP中yield关键字的使用