20200820动态规划(1.零钱兑换 2. 目标和 3.01背包问题 )

这篇博客探讨了动态规划在解决实际问题中的应用,包括从零钱兑换问题出发,如何利用动态规划自底向上的思路找到最优解;接着分析了目标和问题,指出可以采用深度优先搜索(DFS)来求解所有满足条件的方法数;最后讲解了经典的01背包问题,并提到可以通过查阅已有代码来理解解题思路。
摘要由CSDN通过智能技术生成

1.零钱兑换
自己思考的是 首先只有一个变量 就是当前金额余量 ,那么动态规划要自底向上所以要从金额为1开始往上进行计算 这是第一个循环 第二个循环是对于每种硬币
如果硬币面值小于当前金额 就规划 一下 扣掉当前面值之前的数量+1
这个要注意去判断一下是否初值 如果是初值说明无法达到 那么-1

class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {
      if(amount==0)return 0;
      if(amount<0)return -1;
        vector<int>dp(amount+1,amount+2);
        dp[0]=0;
      for(int i=1;i<=amount;i++){
          for(int j=0;j<coins.size();j++){
              if(coins[j]<=i){
                  dp[i]=min(dp[i],dp[i-coins[j]]+1);
              }
          }
      }
      if(dp[amount]==amount+2){return -1;}
      else{
          return dp[amount];
      }
    }
};

2.目标和
这个题很显然 求使得条件满足的所有方法数 那么显然是可以用DFS来做的
很熟练

class Solution {
public:
int ans=0;
    int findTargetSumWays(vector<int>& nums, int S) {
         dfs(nums,S,0,ans);   // 深度优先搜索,枚举出所有结果。
         return ans;
    }
    void dfs(vector<int> &nums,uint target,int left,int &ans){
        if(target == 0 && left == nums.size()) {ans++;
        return;};    // 目标为0并且遍历完了,返回一种方式
        if(left >= nums.size()) return ;       // left大于数组长度,说明都遍历完了,但结果不对,返回0
        dfs(nums,target-nums[left],left+1,ans);    // 给第一个数添加减号,然后递归
        dfs(nums,target+nums[left],left+1,ans);    // 给第一个数添加加号,然后递归
    }
};

3.01背包问题
代码直接可以查到

 #include<stdio.h>
 #include<iostream>
 using namespace std;
 
 int table[10][100]={0};
 int tableTwo[10][100];
 int flag[10]={-1}; 
 
 
 int Knapsack(int v[],int w[],int c,int n){//value weight capacity num 
 	for(int i=1;i<n+1;i++){//因为涉及到i-1的计算,所以下标从1开始 
 		for(int j=1;j<c+1;j++){
 			if(j<w[i]){
 				table[i][j]=table[i-1][j];
 				//flag[i]=0;
 			}else{
 				table[i][j]=max(table[i-1][j],table[i-1][j-w[i]]+v[i]);
 				//flag[i]=table[i-1][j]>(table[i-1][j-w[i]]+v[i])?0:1;
 			}
 		}
 	}
 	return table[n][c];
 }
 int KnapsackTwo(int v[],int w[],int c,int n){//此方法从n->1计算 。自底向上,自左向右 
 	int jMax=min(w[n]-1,c); 
 	for(int j=0;j<jMax;j++)tableTwo[n][j]=0;//j<当前背包容量或者当前物品重量时,tableTwo[n][j]=0; 
 	for(int j=w[n];j<=c;j++)tableTwo[n][j]=v[n];//当前背包容量可以装得下时, tableTwo[n][j]=v[n];
	for(int i=n-1;i>1;i--){
		jMax=min(w[i],c);
		for(int j=0;j<=jMax;j++)tableTwo[i][j]=tableTwo[i+1][j];
		for(int j=w[i];j<=c;j++)tableTwo[i][j]=max(tableTwo[i+1][j],tableTwo[i+1][j-w[i]]+v[i]);//当前背包容量装得下,但是要判断其价值是否最大,确定到底装不装 
	}
	tableTwo[1][c]=tableTwo[2][c];//先假设1物品不装 
	if(c>=w[1])tableTwo[1][c]=max(tableTwo[1][c],tableTwo[2][c-w[1]]+v[1]);//根据价值,判断到底装不装 
	return tableTwo[1][c];//返回最优值 
  }
 void Traceback(int w[],int c,int n){//根据最优值,求最优解 
 	for(int i=1;i<n;i++){
 		if(tableTwo[i][c]==tableTwo[i+1][c])flag[i]=0;
 		else {
 			flag[i]=1;
			c-=w[i];	
 		}
 	}
 	flag[n]=tableTwo[n][c]?1:0;
 }
 
 int main(){
 	int weight[6]={0,2,2,6,5,4};//最低位补了0,从weight[1]开始赋值 
 	int value[6]={0,6,3,5,4,6};
 	int c=10;
 	cout<<"第一种方法->总价值最大为:"<<Knapsack(value,weight,c,5)<<endl;
 	cout<<"第二种方法->总价值最大为:"<<KnapsackTwo(value,weight,c,5)<<endl;
 	Traceback(weight,c,5);
 	cout<<"最优值的解:"; 
 	for(int i=1;i<5+1;i++)cout<<flag[i]<<" ";
 	cout<<endl;
 	for(int i=1;i<6;i++){
 		for(int j=0;j<11;j++){
 			printf("%2d ",tableTwo[i][j]);
 		}
 		cout<<endl;
 	}
 	return 0;
 	
 }
 /*
第一种方法->总价值最大为:15
第二种方法->总价值最大为:15
最优值的解:1 1 0 0 1
 0  0  0  0  0  0  0  0  0  0 15
 0  0  3  3  6  6  9  9  9 10 11
 0  0  0  0  6  6  6  6  6 10 11
 0  0  0  0  6  6  6  6  6 10 10
 0  0  0  0  6  6  6  6  6  6  6
 */
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值