代码改变世界

动态规划算法例题

2018-12-23 20:00  mengjuanjuan1994  阅读(312)  评论(0编辑  收藏  举报

1. 走台阶问题

有n级台阶,一个人每次上一级或者两级,问有多少种走完n级台阶的方法?

方法1:递归

#include <iostream>
using namespace std;

const int N = 100; //假设最多走100级台阶
int result[N]; //保存结果

int step(int n)
{
if(n > 2)
{
result[n] = step(n-1) + step(n-2);
}
return result[n];
}

int main()
{
int n;
cin >> n;
result[1] = 1;
result[2] = 2;
cout << step(n) << endl;
system("pause");
return 0;
}

方法2:自底向上

#include <iostream>
using namespace std;

const int N = 100; //假设最多走100级台阶
int result[N]; //保存结果

int step(int n)
{
for(int i = 3; i <= n; i++)
{
result[i] = result[i-1] + result[i-2];
}
return result[n];
}

int main()
{
int n;
cin >> n;
result[1] = 1;
result[2] = 2;
cout << step(n) << endl;
system("pause");
return 0;
}

2. 求斐波拉契数列Fibonacci

方法1:递归

#include <iostream>
using namespace std;

const int N = 101; //假设最多求到100
int result[N]; //保存结果

int fb(int n)
{
if(n >= 2)
{
result[n] = fb(n-1) + fb(n-2);
}
return result[n];
}

int main()
{
int n;
cin >> n;
result[0] = 0;
result[1] = 1;
cout << fb(n) << endl;
system("pause");
return 0;
}

方法2:自底向上

#include <iostream>
using namespace std;

const int N = 101; //假设最多求到100
int result[N]; //保存结果

int fb(int n)
{
for (int i = 2; i <= n; i++)
{
result[i] = result[i-1] + result[i-2];
}
return result[n];
}

int main()
{
int n;
cin >> n;
result[0] = 0;
result[1] = 1;
cout << fb(n) << endl;
system("pause");
return 0;
}

 

3. 拼凑面额

给你六种面额1、5、10、20、50、100元的纸币,假设每种币值的数量都足够多,编写程序求组成N元(N为0-10000的非负整数)的不同组合的个数。

输入为一个数字N,即需要拼凑的面额。输出也是一个数字,为组成N的组合个数。

#include<iostream>
#include<vector>
using namespace std;

int a[6] = {1, 5, 10, 20, 50, 100};
int main()
{
int n;
cin >> n;
vector<long> dp(n+1, 1);
for(int i = 1; i < 6; i++)
{
for(int j = 1; j <= n; j++)
{
if(j >= a[i])
{
dp[j] = dp[j] + dp[j-a[i]];
}
}
}
cout << dp[n];
system("pause");
return 0;
}

 

4.

给定一个有n个正整数的数组A和一个整数sum,求选择数组A中部分数字和为sum的方案数。当两种选取方案有一个数字的下标不一样,我们就认为是不同的组成方案。 

输入为两行:    第一行为两个正整数n(1 ≤ n ≤ 1000),sum(1 ≤ sum ≤ 1000)第二行为n个正整数A[i](32位整数),以空格隔开。

输出所求的方案数。

输入:

5 15

5 5 10 2 3

输出

4

 

用动态规划, dp(i , j )表示前i 个数中和为 j 的方案数, 则 若 j >= a[i],  dp( i ,j) = dp(i -1, j)+ dp(i - 1,j - a[i] );

否则,  f ( i ,j) = f(i -1, j)。

#include <iostream>
#include <vector>
using namespace std;

long dp[1001][1001];
int main()
{
int n, sum;
cin >>n >> sum;
vector<int> A(n+1, 0);

for(int i = 1; i <= n; i++)
{
cin >> A[i];
}
for (int i = 0; i <= n; i++)
{
for(int j = 0; j <= sum; j++)
{
dp[i][j] = 0;
}
}
dp[0][0] = 1;
for(int i = 1; i <= n; i++)
{
for(int j = 0; j <= sum; j++)
{
if (j >= A[i])
{
dp[i][j] = dp[i-1][j] + dp[i-1][j-A[i]];
}
else
{
dp[i][j] = dp[i-1][j];
}
}
}
cout << dp[n][sum];
system("pause");
return 0;
}

 

优化的方法为:由于二维数组中,第i行 只与第 i - 1 行有关,所有我们若从 最后一列 开始更新数组,则可用一维数组来保存先前状态。

#include <iostream>
#include <vector>
using namespace std;

int main()
{
int n, sum;
cin >>n >> sum;
vector<int> A(n+1, 0);
vector<long> dp(sum+1, 0);
for(int i = 1; i <= n; i++)
{
cin >> A[i];
}
dp[0] = 1;
for(int i = 1; i <= n; i++)
{
for(int j = sum; j >= A[i]; j--)
{
dp[j] = dp[j] + dp[j-A[i]];
}
}
cout << dp[sum];
system("pause");
return 0;
}

 

 

5.

#include<iostream>
#include <vector>
#include <time.h>
using namespace std;
/*
在一条直线上,有n个房屋,每个房屋中有数量不等的财宝,有一个盗贼希望从房屋中盗取财宝,由于房屋中有报警器,
如果同时从相邻的房屋中盗取财宝就会触发报警器。问不触发报警器的前提下,最多可获取多少财宝

输入 [5 2 6 3 1 7] 输出 5 + 6 + 7 = 18
*/
int rob(vector<int> &nums)
{
//设dp[i]为前i个房屋中可获取的财宝, dp[i] = max{dp[i-1], dp[i-2] + nums[i]}
vector<int> dp(nums.size() + 1, 0);
dp[0] = 0;
dp[1] = nums[0];
for (int i = 2; i < nums.size() + 1; i++)
{
if (dp[i-1] > dp[i-2] + nums[i-1])
{
dp[i] = dp[i-1];
}
else
{
dp[i] = dp[i-2] + nums[i-1];
}
}
return dp[nums.size()];
}
int main()
{
vector<int> nums(6);
srand((unsigned int)time(NULL));
for (int i = 0; i < 6; i++)
{
nums[i] = rand() % 20 + 1;
cout << nums[i] << " ";
}
cout << endl;
cout << rob(nums) << endl;
system("pause");
return 0;
}

 

 

6.

#include<iostream>
#include <vector>
#include <time.h>
using namespace std;
/*
给定一个数组,求这个数组的连续子数组中,最大的那一段的和
如数组[-2, 1, -3, 4, -1, 2, 1, -5, 4] , 最大的和是[4, -1, 2, 1], 为6
*/
int maxSubArray(vector<int> &nums)
{
//设dp[i]为包含第i项的最大子列和
//dp[i-1] > 0, 则dp[i] = dp[i-1] + nums[i]. 否则 dp[i] = nums[i]
vector<int> dp(nums.size(), 0);
int max_res = nums[0];
dp[0] = nums[0];
for (int i = 1; i < nums.size(); i++)
{
if (dp[i-1] > 0)
{
dp[i] = dp[i-1] + nums[i];
}
else
{
dp[i] = nums[i];
}
if (max_res < dp[i])
{
max_res = dp[i];
}
}

return max_res;
}
int main()
{
vector<int> nums(8);
srand((unsigned int)time(NULL));
for (int i = 0; i < 8; i++)
{
nums[i] = rand() % 10 - 5;
cout << nums[i] << " ";
}
cout << endl;
cout << maxSubArray(nums) << endl;
system("pause");
return 0;
}

 

 

#include<iostream>
#include <vector>
#include <time.h>
using namespace std;
/*
已知不同面值的钞票,求如何用最少数量的钞票组成某个金额,求可以使用的最少钞票数量,
如果任意数量的已知面额钞票都无法组成该金额,则返回-1

[1, 2, 5] 11 返回3
[2] 3 返回-1
[1, 2, 5, 7, 10] 14 返回2
*/
int coinChange(vector<int> &coins, int amount)
{
//设dp[i]为面额为i 的最少钞票个数
//若dp[i-coins[j]]全为-1, 则返回-1, 否则 dp[i] = 1 + max(dp[i-coins[j]])
vector<int> dp(amount+1, -1);
dp[0] = 0;
for (int i = 1; i < amount + 1; i++)
{
for (int j = 0; j < coins.size(); j++)
{
if (i >= coins[j] && dp[i-coins[j]] != -1 && (dp[i] == -1 || dp[i] > dp[i-coins[j]] + 1))
{
dp[i] = dp[i-coins[j]] + 1;
}
}
}
return dp[amount];
}
int main()
{
vector<int> nums(5);
srand((unsigned int)time(NULL));
for (int i = 0; i < 5; i++)
{
nums[i] = rand() % 10 + 1;
cout << nums[i] << " ";
}
cout << endl;
cout << coinChange(nums, 13) << endl;
system("pause");
return 0;
}

 

 

 

 

#include<iostream>
#include <vector>
#include <time.h>
using namespace std;
/*
给定一个二维数组,其保存了一个数字三角形,求从数字三角形顶端到低端各数字和最小的路径之和,
每次可以向下走相邻的两个位置

[2]
[3, 4]
[6, 5, 7]
[4, 1, 8, 3]
返回11

*/
int minimumTotal(vector<vector<int> > triangle)
{
//设dp[i][j]为第i行,第j列的最小路径和,从最后一行一直推到第一行
int n = triangle.size();
vector<vector<int> > dp(n);
for (int i = 0; i < triangle[n-1].size(); i++)
{
dp[n-1].push_back(triangle[n-1][i]);
}
for (int i = n-2; i >= 0; i--)
{
for (int j = 0; j < triangle[i].size(); j++)
{
if (dp[i+1][j] < dp[i+1][j+1])
{
dp[i].push_back(dp[i+1][j] + triangle[i][j]);
}
else
{
dp[i].push_back(dp[i+1][j+1] + triangle[i][j]);
}
}
}
return dp[0][0];
}
int main()
{
vector<int> temp;
vector<vector<int> > triangle;
temp.push_back(2);
triangle.push_back(temp);
temp.clear();
temp.push_back(3);
temp.push_back(4);
triangle.push_back(temp);
temp.clear();
temp.push_back(6);
temp.push_back(5);
temp.push_back(7);
triangle.push_back(temp);
temp.clear();
temp.push_back(4);
temp.push_back(1);
temp.push_back(8);
temp.push_back(3);
triangle.push_back(temp);
cout << minimumTotal(triangle) << endl;
system("pause");
return 0;
}