/*
参考书:算法设计技巧与分析 M.H.Alsuwaiyel著 吴伟旭 方世昌译
----------------------------------------------------------------
1.递归 将问题分成相似的子问题
1.1Fabonacci问题
递归会导致重复计算,时间复杂度为o(2^n),因为函数压栈,空间复杂度o(n)
非递归 时间复杂度为o(n),空间复杂度为o(1)
----------------------------------------------------------------
2. 动态规划
找到递推公式,从底向上,再计算下一个问题时,上一个问题已经解决,可以直接调用之前的结果
一般都是对于问题建一个矩阵,找到递推公式
2.1 最长公共子序列 LCS
对于 a1a2.....ai and b1b2......bj 最长公共子序列的长度为 L[i,j]
if i==0||j==0 then L[i,j]=0
else if ai==bj then L[i,j]=l[i-1,j-1]+1 else L[i,j]=max{L[i-1,j],L[i,j-1]}
2.2 矩阵链相乘
2.3 背包问题 KNAPSACK
0/1背包问题
将n个物品放入C大小的背包中,求V[n,C]的最大值,放入物品的最大价值
V[i,j]表示将前i个物品放入大小为j的空间中的最大价值,V的size是n+1 * C+1
si,vi分别是物品ui的大小和价值
if i==0||j==0 then V[i,j]=0;
else if j<si then V[i,j]=V[i-1,j]
else if i>0&&j>=si then v[i,j]=max{V[i-1,j],V[i-1,j-si]+vi}
2.4 金钱兑换问题 money_exchange
一个货币系统,有n种硬币,面值为 v1v2v3....vn,其中v1=1,
现在兑换价值为y的钱,要让硬币数目最少
即在约束 sum(xi*vi)=y的情况下 sum(xi)最小 其中i=[1....n]
N[i,j]表示前i种硬币兑换j的钱最少的硬币数
初始化 N[0][j]=INF N[1][j]=j N[i][0]=0
if vi>j then N[i,j]=N[i-1,j] else N[i,j]=min{N[i-1,j-kvi]+k,N[i-1,j]}
return N[n][y]
----------------------------------------------------------------
2.最短路径问题(Dijkstra)
-----------------------------------------------------------------
3.最小耗费生成树(Kruskal)
4.最小耗费生成树(Prim)
*/
#include <iostream>
#include <vector>
#include <array>
#include <list>
#include <stack>
#include <map>
#include <set>
#include <algorithm>
#include <random>
#include <Windows.h>
using namespace std;
std::default_random_engine generator;
#define INF 99999
/*
均匀分布uniform,正态分布normal,二项分布binomial,泊松分布poisson
*/
std::uniform_int_distribution<int> dis(1, 9);
void myRandom(vector<int>&datasets, int n) {
for (int i = 0; i < n;i++)
datasets.push_back(dis(generator));
}
int Fibonacci1(int n) {
if (n == 1 || n == 2) return 1;
return Fibonacci1(n - 1) + Fibonacci1(n - 2);
}
int Fibonacci2(int n) {
//assert(n >= 0);
int first = 0;
int secend = 1;
int third = 0;
for (int i = 2; i <= n; i++) {
third = secend + first;
first = secend;
secend = third;
}
return third;
}
//最长公共子序列
int LCS(int n, int m) {
vector<int> a, b;//序列a,b
myRandom(a, n);
myRandom(b, m);
for_each(a.begin(), a.end(), [](auto &it) {cout << it << '\t'; });
cout << endl;
for_each(b.begin(), b.end(), [](auto &it) {cout << it << '\t'; });
cout << endl;
//矩阵大小是n+1 * m+1
vector<vector<int>> L(n+1);
for_each(L.begin(), L.end(), [&](auto &each) {swap(each, vector<int>(m+1, 0)); });
//for (int i = 0; i < n; i++)
// L.push_back(vector<int>(m, 0));
//for (auto it = L.begin(); it != L.end(); it++)
// cout << it->at(1) << endl;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {//注意边界
if (a[i - 1] == b[j - 1]) L[i][j] = L[i - 1][j - 1] + 1;
else L[i][j] = max(L[i - 1][j], L[i][j - 1]);
}
}
return L[n][m];
}
//0/1背包问题
int KNAPSACK(int n,int C) {
vector<int> s;//大小
vector<int> v;//价值
myRandom(s, n);
myRandom(v, n);
for_each(s.begin(), s.end(), [](auto &it) {cout << it << '\t'; });
cout << endl;
for_each(v.begin(), v.end(), [](auto &it) {cout << it << '\t'; });
cout << endl;
vector<vector<int>>V(n+1);
for_each(V.begin(), V.end(), [&](auto &each) {swap(each, vector<int>(C + 1, 0)); });
//for (auto it = V.begin(); it != V.end(); it++)
// cout << it->at(1) << endl;
for (int i = 1; i <= n; i++) { //注意下标的意义,i对应的物体是s[i-1],和V有点不同
for (int j = 1; j <= C; j++) {
if (j < s[i-1]) V[i][j] = V[i - 1][j];
else if (j >= s[i-1]) V[i][j] = max(V[i - 1][j] ,V[i - 1][j - s[i-1]] + v[i-1]);
}
}
return V[n][C];
}
//金钱兑换问题 P143 (7.30)
int MoneyExchange(int n, int y) {
if (n == 1) return y;
vector<int> v;//硬币面值
myRandom(v, n);
v[0] = 1;
sort(v.begin(), v.end());//其实这一步排序不必要,因为保证了了v[0]=1是基本硬币
for_each(v.begin(), v.end(), [](auto &it) {cout << it << '\t'; });
cout << endl;
vector<vector<int>> N(n+1);
for_each(N.begin(), N.end(), [&](auto &each) {swap(each, vector<int>(y + 1, INF)); });
for (int i = 0; i <= y; i++) {
N[1][i] = i;
}
for (int i = 1; i <= n; i ++ ) {
N[i][0] = 0;
}
for (int i = 2; i <= n; i++) {
for (int j = 1; j <= y; j++) {
N[i][j] = N[i - 1][j];//如果不要这个v[i-1]
if (v[i - 1] <= j) {
int num = j / v[i - 1];
vector<int> temp;
//temp.push_back(N[i][j]);
for (int k = 0; k <= num; k++) {
temp.push_back(N[i - 1][j - k*v[i - 1]] + k);
}
sort(temp.begin(), temp.end());
N[i][j] = temp[0];
}
}
}
return N[n][y];
}
void test_Fibonacci(int n) {
cout << "Fibonacci:\n";
long t1 = GetTickCount();
cout << Fibonacci2(n) << endl;
long t2 = GetTickCount();
cout << t2 - t1 << endl;
cout << Fibonacci1(n) << endl;
long t3= GetTickCount();
cout << t3 - t2 << endl;
//cout << vec.size() << endl;
}
void test() {
//test_Fibonacci(35);
cout << "LCS:\n";
cout<<LCS(10, 10)<<endl;
cout << "KNAPSACK:\n";
cout << KNAPSACK(5, 20)<<endl;
cout << "MoneyExchange:\n";
cout << MoneyExchange(6, 100) << endl;
}
int main() {
test();
system("pause");
return 0;
}
c++学习笔记:动态规划(最长公共子序列,01背包问题,金钱兑换问题)
猜你喜欢
转载自blog.csdn.net/u010548772/article/details/80808656
今日推荐
周排行