动态规划总结

来源:互联网 发布:centos 7.2安装选项 编辑:程序博客网 时间:2024/06/09 21:36

问题1,有数组penny,penny中所有的值都为正数且不重复。每个值代表一种面值的货币,每种面值的货币可以使用任意张,再给定一个整数aim(小于等于1000)代表要找的钱数,求换钱有多少种方法。

给定数组penny及它的大小(小于等于50),同时给定一个整数aim,请返回有多少方法可以凑成aim。

方法一:暴力搜索

int countWays(vector<int> penny, int aim) 
{
if (penny.empty() || aim <= 0){
return 0;
}
return process(penny, 0, aim);
}

int process(vector<int> penny, int index, int aim){
int res = 0;
if (index == (penny.size() - 1)){
res = (aim % penny[index])?0:1;
return res;
}
else
{
res = 0;
int k = aim / penny[index];
for (int i = 0; i < k; ++i){
res += process(penny, index + 1, aim - i * penny[index]);
}
}
return res;
}

方法二:动态规划
int countWays(vector<int> penny, int aim){
if (penny.empty() || aim <= 0){
return 0;
}
int dp[penny.size()][aim + 1] = {0};
for (int i = 0; i < penny.size(); ++i){
dp[i][0] = 1;
}
for (int i = 1; i < aim + 1; ++i){
if (i % penny[0] == 0){
dp[0][i] = 1;
}
}
for (int i = 1; i < penny.size(); ++i){
for (int j = 1; j < aim + 1; ++j){
if (j >= penny[i]){
dp[i][j] = dp[i - 1][j] + penny[i][j - penny[i]];
}
else
dp[i][j] = dp[i - 1][j];
}
}
return dp[penny.size() - 1][aim];
}


什么是动态规划方法?

1、其本质是利用申请的空间来记录每一个暴力搜索的计算结果,下次要用结果的时候直接使用,而不在进行重复的递归过程。

2、动态规划规定每一种递归状态的计算顺序,依次进行计算。

动态规划方法的关键点:

1、最优化原理,也就是最优子结构性质。这指的是一个最优化策略具有这样的性质,不论过去状态和决策如何,对面前的决策所形成的状态而言,余下的决策必须构成最优策略。简单来说就是一个最优化策略的子策略总是最优的,如果一个问题满足最优化原理,就称其具有最优子结构性质。

2,、无后效性。指的是某状态下决策的收益,只与状态和决策相关,与到达该状态的方式无关。

3、子问题的重叠性,动态规划将原来具有指数级时间复杂度的暴力搜索算法改进成了具有多项式时间复杂度的算法。其中的关键在于解决多余,这是动态规划算法的根本目的。


问题1.给定一个矩阵m,从左上角开始每次只能向右或者向下走,最后到达右上角的位置,路径上所有的数字累加起来就是路径和,返回所有的路径中最小的路径和。如果给定的m如大家看到的样子,路径1,3,1,0,6,1,0是所有路径中路径和最小的,所以返回12.

1 3 5 9

8 1 3 4

5 0 6 1

8 8 4 0

int getMin(vector<vector<int> > map, int n, int m) {int dp[n][m] = {0};dp[0][0] = map[0][0];for (int i = 1; i < n; ++i){dp[i][0] += dp[i - 1][0] + map[i][0];}for (int i = 1; i < m; ++i){dp[0][m] += dp[0][i - 1] + map[0][i];}for (int i = 1; i < n; ++i){for (int j = 1; j < m; ++j){dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + map[i][j];}}return dp[n - 1][m -1];}
问题2.给定数组arr,返回arr的最常递增子序列长度。比如arr=[2,1,5,3,6,4,8,9,7],最长递增子序列为[1,3,4,8,9],所以返回这个子序列的长度为5.给定数组arr,返回arr的最长递增子序列长度。比如arr=[2,1,5,3,6,4,8,9,7],最长递增子序列为[1,3,4,8,9],所以返回这个子序列的长度5.

int getLIS(vector<int> A, int n) {int dp[n] = 0;dp[0] = 1;for (int i = 1; i < A.size(); ++i){int j = 0;int max = 0;while(j < i){if (A[j] < A[i] && dp[j] > max){max = dp[j];}++j}dp[i] = max + 1;}int res = 0;for(int i=0;i<A.size();i++)if(res<dp[i])res=dp[i];return res;}
问题3.给定两个字符串str1和str2,返回两个字符串的最长公共子序列。例如,str1 = “1A2C3D4B56”,str2="B1D23CA45B6A",“12345”或者“12C4B6”都是最长公共子序列,返回哪一个都行。

int findLCS(string A, int n, string B, int m) {int **dp=new int*[n];for(int i=0;i<n;i++)dp[i]=new int[m];for(int i=0,temp=0;i<n;i++){if(B[0]==A[i])temp=1;dp[i][0]=temp;}for(int i=0,temp=0;i<m;i++){if(A[0]==B[i])temp=1;dp[0][i]=temp;}for(int i=1;i<n;i++)for(int j=1;j<m;j++){int m=max(dp[i-1][j],dp[i][j-1]);if(A[i]==B[j])m=max(dp[i-1][j-1]+1,m);dp[i][j]=m;}return dp[n-1][m-1];}
问题4.一个背包有一定的承重W,有N件物品,每件都有自己的价值,记录在数组v中,也都有自己的重量,记录在数组w中,每件物品只能选择要装入背包还是不装入背包,要求在不超过背包承重的前提下,选出物品的总价值最大。

int maxValue(vector<int> w, vector<int> v, int n, int cap)           {                  int **dp=new int*[n];                  for(int i=0;i<n;i++)                          dp[i]=new int[cap+1]();                  for(int i=0;i<n;i++)                          dp[i][0]=0;                  for(int i=0;i<cap+1;i++)                  {                          if(i>=w[0])                                 dp[0][i]=v[0];                          else                               dp[0][i]=0;                  }                  for(int i=1;i<n;i++)                          for(int j=1;j<cap+1;j++)                      {                               if((j-w[i])>=0)                                       dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+v[i]);                               else                                     dp[i][j]=dp[i-1][j];                      }                      int res=dp[n-1][cap];                      for(int i=0;i<n;i++)                          delete []dp[i];                  delete []dp;                  return res;          } 
问题5.给定两个字符串str1和str2,再给定三个整数ic、dc和rc,分别代表插入、删除和替换一个字符的代价。返回将str1编辑成str2的最小代价。比如,str=“abc”,str2=’adc‘,ic=5,dc= 3,rc=2.从“abc”编辑成“adc”,把’b‘替换成’d‘是代价最小的,所以返回2.再比如,str1=’abc‘,str2=’adc‘,ic=5,dc=3,rc=100.从’abc‘编辑成“adc”,先删除’b‘,然后插入’d‘是代价最小的,所以返回8.

int findMinCost(string A, int n, string B, int m, int c0, int c1, int c2) //c0插入,c1删除,c2替换{int **dp=new int*[n+1];for(int i=0;i<n+1;i++)dp[i]=new int[m+1];for(int i=0;i<n+1;i++)dp[i][0]=i*c1;for(int i=0;i<m+1;i++)dp[0][i]=i*c0;for(int i=1;i<n+1;i++)for(int j=1;j<m+1;j++){int temp1=0,temp2=0,res;temp1=min(dp[i][j-1]+c0,dp[i-1][j]+c1);if(A[i-1]==B[j-1])temp2=dp[i-1][j-1];elsetemp2=dp[i-1][j-1]+c2;res=min(temp1,temp2);dp[i][j]=res;}return dp[n][m];}