一:贪心
C++的贪心算法是一种基于贪心策略的算法,其中贪心策略是根据当前状态做出局部最优的选择,以期望最终能够得到全局最优解。
贪心算法通常用于寻找最优解问题,尤其是当问题具有最优子结构性质时,即问题的最优解可以通过其子问题的最优解来推导得出。在这种情况下,贪心策略通常表现出良好的性能,并且可以很容易地被实现。
在C++中,可以使用一些基本数据结构和算法来实现贪心算法。例如,可以使用STL中的vector、set、map等容器,以及sort、lower_bound等算法来实现贪心算法。
下面是一个简单的例子,展示了如何使用贪心算法解决一个经典问题:
题目:你有一笔钱,你需要用这笔钱买下一些物品。每个物品有一个价格和价值,你可以购买任意数量的物品,但是你的钱不足以买下所有的物品。你的任务是选择一些物品,使得它们的总价值最大。
解决方案:首先,我们可以将所有的物品按照价值从大到小排序。然后,我们从价值最高的物品开始选择,一直到我们的钱花完为止。在这个过程中,我们不断地选择价值高的物品,以期望得到最大的总价值。
C++代码实现如下:
#include<bits/stdc++.h>
using namespace std;
int n,m;
struct node
{
int val,num; // val是价值,num是钱数
}a[1000001];
bool cmp(node x,node y)
{
return x.val>y.val;
}
int cnt=0;
int main()
{
cin>>n>>m;//m是我有的钱
for(int i=1;i<=n;i++)
cin>>a[i].num>>a[i].val;
sort(a+1,a+1+n,cmp);
for(int i=1;i<=n;i++)
{
if(m-a[i].num>0)
{
cnt+=a[i].val;
m-=a[i].num;
}
else break;
}
cout<<cnt;
return 0;
}
在这个例子中,我们首先定义了一个node结构体,表示每个物品的价格和价值。然后,我们定义了一个比较函数cmp,用于将物品按照价值从大到小排序。
在主函数中,我们将所有物品按照价值排序,然后从价值最高的物品开始选择,直到我们的钱花完为止。在每次选择中,我们都减去物品的价格,并将其价值加入总价值中。
最终,我们输出总价值,即为最优解。
总之,贪心算法是一种简单而有效的解决最优化问题的方法,在C++中有很多容器和算法可以帮助我们实现贪心策略。通过不断练习和挑战复杂问题,我们可以更好地掌握和应用贪心算法。
二:动态规划
动态规划是一种常用的算法方法,用于解决具有最优子结构性质的问题。它可以帮助我们解决很多复杂的问题,比如字符串匹配、最长公共子序列、背包问题等等。在C++编程中,动态规划算法也是一种非常重要的算法方法。
动态规划的基本思想是将问题分解为若干个子问题,并将子问题的解存储在一个表格中。然后基于已有的子问题的解,通过一定的规则来推导出更大的问题的解。通常情况下,动态规划都采用自底向上的方式,先求解小问题,再根据小问题的解来求解大问题。
C++中,动态规划算法通常采用数组来存储子问题的解。我们可以使用for循环来遍历数组,求出每个子问题的解,然后根据之前的子问题的解来计算当前问题的解。下面我们通过一个例子来讲解动态规划算法的具体实现。
背包问题是动态规划算法的经典问题之一。其基本思想是,有一个容量为C的背包和n个物品,每个物品有一个重量和一个价值,我们的目标是找出一组物品,使得它们的总重量不超过C,同时总价值最大。为了解决这个问题,我们需要使用动态规划算法。
首先,我们定义一个二维数组dp[n+1][C+1],其中dp[i][j]表示前i个物品中,容量为j的背包能够存放的最大价值。然后我们可以使用下面的代码来求解背包问题:
int n, C; //n表示物品的数量,C表示背包的容量
int w[maxn], v[maxn]; //w表示每个物品的重量,v表示每个物品的价值
int dp[maxn][maxn]; //dp[i][j]表示前i个物品中,容量为j的背包能够存放的最大价值
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= C; j++) {
if (j < w[i]) { //当前物品无法放入背包中
dp[i][j] = dp[i-1][j];
}
else {
//将当前物品放入背包中或者不放入背包中,取两者中较大的一个
dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i]]+v[i]);
}
}
}
上述代码中,我们使用两个for循环来遍历dp数组,求解每个子问题的解。当j < w[i]时,表示当前物品无法放入背包中,此时我们可以继承上一个状态的价值;当j >= w[i]时,表示当前物品可以放入背包中,此时我们需要选择将当前物品放入背包中还是不放入背包中,取两者中较大的一个。
在实际使用中,为了节省空间,我们通常可以将二维数组dp[n+1][C+1]优化为一维数组dp[C+1]。这样,我们只需要一个一维数组就可以存储所有子问题的解,从而达到空间优化的目的。
int dp[maxn]; //dp[i]表示容量为i的背包能够存放的最大价值
for (int i = 1; i <= n; i++) {
for (int j = C; j >= w[i]; j--) {
dp[j] = max(dp[j], dp[j-w[i]]+v[i]);
}
}
三:动态规划与贪心的差别
C++动态规划与贪心算法都是解决最优解问题的常用算法方法,但它们的核心思想和应用场景略有不同。
动态规划算法是一种将复杂问题分解为简单子问题的方法,在求解复杂问题时,动态规划算法通常需要关注问题的最优子结构性质,即问题的最优解可以由子问题的最优解推导而来。动态规划算法的基本思想是将问题分解为若干个子问题,并将子问题的解存储在一个表格中。然后基于已有的子问题的解,通过一定的规则来推导出更大的问题的解。
相比之下,贪心算法的核心思想是在每一步选择中都采取当前状态下最优的选择,以期望能够得到全局最优解。贪心算法通常不需要依赖于问题的最优子结构性质,而是通过设计合适的贪心策略来达到最优解的目的。
下面我们通过一个例子来说明动态规划算法和贪心算法的区别:
假设我们有一个货车可以坐n个人,现在有m个人要搭车,每个人的重量不同。假设我们的目标是让这些人尽可能地坐在一辆车上,且不超过货车的最大载重。那么我们可以使用贪心算法来解决这个问题。我们可以将这些人按照体重从轻到重的顺序排序,然后从轻到重依次让他们上车,直到车上的人数达到了n或者车的载重已经达到了上限。这个贪心策略可能不是全局最优解,但在实际使用中通常可以得到一个不错的解。
然而,如果我们希望得到全局最优解,就需要使用动态规划算法。我们可以定义一个二维数组dp[i][j],其中dp[i][j]表示前i个人中,体重不超过j的情况下,可以坐在一辆车上的最大人数。我们可以按照以下方式递推计算dp数组:
- 对于第i个人,如果他的体重大于j,则dp[i][j] = dp[i-1][j],即他不能上车;
- 如果他的体重小于等于j,则有两种情况:他可以上车或者他不能上车。如果他可以上车,那么dp[i][j] = dp[i-1][j-w[i]] + 1,如果他不能上车,那么dp[i][j] = dp[i-1][j]。取这两者中较大的一个即可。
最后,dp[n][j]中的j就是能够坐在一辆车上的最大载重。这种方法可以保证得到全局最优解。
综上所述,动态规划算法和贪心算法都是解决最优解问题的有效方法。在具体问题中,我们需要根据问题的性质来选择合适的算法。