动态规划初步进阶(一)

如果我们有面值为1元、3元和5元的硬币若干枚,如何用最少的硬币凑够11元?

  动态规划的思想:1.当我们遇到一个大问题时,总是习惯把问题的规模变小,这样便于分析讨论。 2.这个规模变小后的问题和原来的问题是同质的,除了规模变小,其它的都是一样的,本质上它还是同一个问题(规模变小后的问题其实是原问题的子问题.

   动态规划的求解过程中有两个概念:状态和状态转移方程。状态就是如何描述这个问题并且如何求解的过程。在这个问题中。可以采用dp(i)=j来表示i元由j个硬币组成的。表示出了这个子问题过后,进行如何求解的过程。dp(0)=0表示0元由0个硬币组成,dp(1)=dp(1-1)+1,表示拿起一个面值为1的硬币,接下来只需要凑够0元即可,而这个是已经知道答案的,即d(0)=0。在大部分的动态规划中都有当前状态依赖于前一个状态,并且独立于后面的状态。要当前所求的值最小,只要满足前一个依赖的状态最小就可以达到要求。再接下来分析,dp(2)=dp(2-1)+1,因为还是只有1元硬币可以使用。所以只能取一个一元的硬币,凑够dp(1)就即可。在dp(3)时可以有两种取法。一种是dp(3)=dp(3-1)+1或者dp(3)=dp(3-3)+1.分别表示取一个一元硬币各先取3元硬币,就有两种值。从这些状态中我们可以推出状态转移方程:d(i)=min{ d(i-vj)+1 },其中i-vj >=0,vj表示第j个硬币的面值;有了状态转移方程,就可以很快解决这个问题。具体代码如下:

#include <iostream>
using namespace std;

int main(){
    int num[100],V[3]={1,3,5};
	int N=11;
	int i,j;

	for(i=0;i<100;i++) ////进行数据初始化
		num[i]=1000;

	num[0]=0;  ////问题起点
	for(i=1;i<=N;i++)////求得每一个dp{i]
	{
		for(j=0;j<3;j++) 
			if(V[j]<=i && num[i-V[j]]+1 < num[i])///进行判断查找最大值
				num[i]=num[i-V[j]]+1;
	     cout<<i<<":"<<num[i]<<endl; ///输出每种情况
	}
	cout<<num[N]<<endl;///输出最小硬币数目
    return 0;
}

附上运行结果示截图:

猜你喜欢

转载自blog.csdn.net/lovequanquqn/article/details/51458072
今日推荐