【算法学习】---(二)动态规划

本节算法:动态规划

动态规划:与分治法类似,也是将大规模的问题分解为若干个子问题,先求解子问题,再从这些子问题的解得到原问题的解。但是动态规划解决的这些问题,他们经分解后的子问题往往是互相不独立的。这时候,再用分治法解决就会耗费大量的时间。且在这过程中,会有一些子问题被我们进行重复求解,很不划算。
因此,出现动态规划思想:如果将已经解决的子问题的解保存到一张表中,不管该子问题以后是否被用到,只要他被计算过,就将其结果填入表中。

动态规划算法步骤

  1. 找出最优子结构性质,并刻画其结构特征
  2. 递归的定义最优值
  3. 以自底向上的方式计算出最优值
  4. 构造最优解

浅试一下:

最长公共子序列问题:

给定两个序列X = <x1,x2,…,xm>和Y = <y1,y2,…,yn>,求X和Y长度最长的公共子序列。比如:


dp[m][n]则存储两个字符串的最长公共子序列长度

写出动态规划的最优解计算公式:
在这里插入图片描述
具体实现:

template<class T>
void Print_Vec(vector<vector<T> >& c)
{
	int m = c.size();
	for (int i = 0; i < m; ++i)
	{
		int n = c[i].size();
		for (int j = 0; j < n; ++j)
		{
			cout << setw(3) << c[i][j];
		}
		cout << endl;
	}
	cout << endl;
}

int LCSLength(const char* X, const char* Y, int m, int n,
	vector<vector<int> >& c, vector<vector<int> >& s)
{
	if (m == 0 || n == 0) return 0;
	else if (c[m][n] != 0) return c[m][n];
	else
	{
		if (X[m] == Y[n])
		{
			c[m][n] = LCSLength(X, Y, m - 1, n - 1, c, s) + 1;
			s[m][n] = 1;
		}
		else
		{
			int max1 = LCSLength(X, Y, m - 1, n, c, s);
			int max2 = LCSLength(X, Y, m, n - 1, c, s);
			if (max1 > max2)
			{
				c[m][n] = max1;
				s[m][n] = 2;
			}
			else
			{
				c[m][n] = max2;
				s[m][n] = 3;
			}
		}
	}
	return c[m][n];
}

int LCS(string& X, string& Y,vector<vector<int> >&c, vector<vector<int> >& s)
{
	int n = X.size() - 1;
	int m = Y.size() - 1;
	for (int i = 0; i <= n; ++i) c[i][0] = 0;
	for (int j = 0; j <= m; ++j) c[0][j] = 0;
	for (int i = 1; i <= n; ++i)
	{
		for (int j = 1; j <= m; ++j)
		{
			if (X[j] == Y[i])
			{
				c[i][j] = c[i - 1][j - 1] + 1;
				s[i][j] = 1;
			}
			else
			{
				//c[i][j] = max(c[i - 1][j], c[i][i - 1]);
				if (c[i - 1][j] > c[i][j - 1])
				{
					c[i][j] = c[i - 1][j];
					s[i][j] = 2;
				}
				else
				{
					c[i][j] = c[i][j - 1];
					s[i][j] = 3;
				}
			}
		}
	}
	return c[n][m];
}
int main()
{
	string X= { "#ABCBDAB" };
	string Y= { "#BDCABA" };
	int xm = X.size()- 1, yn = Y.size() - 1;
	vector<vector<int> > c, s;
	c.resize(xm + 1);
	s.resize(xm + 1);
	for (int i = 0; i < xm + 1; ++i)
	{
		c[i].resize(yn + 1, 0);
		s[i].resize(yn + 1, 0);
	}
	int maxlen = LCS(X, Y, c, s);
	cout << maxlen << endl;
	Print_Vec(c);
	Print_Vec(s);
	return 0;
}

打印出中间动态规划的表,方便理解算法的走向
在这里插入图片描述


算法练习:

在这里插入图片描述
写出最优解计算公式:
在这里插入图片描述

具体实现:

//打家劫舍:相邻不能偷
int Rob(vector<int>& values, int* dp)
{
	int n = values.size();
	if (n == 0) return 0;
	for (int i = 1; i < n; ++i)
	{
		if (i == 1)
		{
			dp[i] = values[i];
		}
		else if (i == 2)
		{
			dp[i] = values[1] > values[2] ? values[1] : values[2];
		}
		else
		{
			dp[i] = std::max(dp[i - 1], dp[i - 2] + values[i]);
		}
	}
	return dp[n];
}

int main()
{
	vector<int> nums = { 0,1,2,3,1 };//0下标不存,方便计算
	int n = nums.size();
	int* dp = new int[n+1];
	cout << Rob(nums,dp);

	delete []dp;
	return 0;
}

总结

主要是,在不同的情况之下,写出符合当前情况的最优解的计算公式,就可以很好的编程了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值