7.哀家要长脑子了!

二分

先把昨天解决的二分问题给写了,就是前几天那个寻找食物储量的问题

寻找食物储量 - 蓝桥云课 (lanqiao.cn)

#include <iostream>
using namespace std;
int n, x[1000010];
int main()
{
  cin >> n;
  for(int i = 1; i <= n; i++){
    cin >> x[i];
  }
  int target;
  cin >> target;
  int left = 0, right = n;
  while(left < right){
    int middle = left + ((right - left) / 2);
    if(x[middle] > target){
      right = middle;
    }
    else {
      left = middle + 1;
    }
  }
  if(x[n] < target){
    cout << -1;
  }
  else {
    cout << left;
  }
  return 0;
}

这个题当时有40%过不了有两个原因,一是当时数组开的太小了,二分我把middle定义在了外面,应该要定义在里面,但是我不明白为什么不能定义在循环外,文心一言这老弟说不出个所以然来

二分模板一:

while(left <= right){
        if(nums[mid] > target){

                right = mid - 1;

        }

        else if(nums[mid] < target){

                left = mid + 1;;

        }

        else 

                break;

}

注意:这里一定不能写成左闭右闭

while(left < right){

        if(nums[mid] > target){

                right = mid;

        }

        else if(nums[mid] < target){

                left = mid + 1;

        }

        else

               break;

}

注意区间和边界值 

继续写完,昨天就写了一道题。。。。果然还是不能拖 今日事今日毕 明日复明日 明日何其多啊!

1.取钱 - 蓝桥云课 (lanqiao.cn)

这是一道以前有一次没有搞定的题目,当时用的是模拟,样例也能通过,但是答案只能过60% 

原来是要用动态规划啊~~~ 让我来看看呢

动态规划是给定一个问题,把它拆成一个个子问题,直到子问题可以直接解决。然后把子问题答案保存起来,以减少重复计算。再根据子问题答案反推,得出原问题答案的一种方法。

现在让我直接讲,我还讲不出,我又只能对着代码讲,写自己的理解了TAT

#include <bits/stdc++.h>  
using namespace std;  
const int N = 10e5; 
int main() {  
    int money[5] = {1, 4, 5, 10, 20};
    int n;
    while(cin >> n){
    // 这个很重要!一定要明确dp数组的含义是什么,它的作用是什么
    // 这里dp数组的含义是凑齐金额i所需的最少钞票张数 
    int dp[n + 1];  
    for(int i = 0; i <= n; i++){  
        dp[i] = N; // 所有值初始化为无穷大  
    } 
    // 表示凑齐金额为0 所需的最少钞票张数是0张
      dp[0] = 0;
    // 遍历从0到所要凑齐的金额n
      for(int i = 0; i <= n; i++){
    // 内循环遍历面值
        for(int j = 0; j < 5; j++){
    //如果当前的金额i能够使用当前的面值money[j](下面我称为x 代表此时的第j张为x元)支付
          if(i - money[j] >= 0){
     /* 可以使用一张面值为 j 的钞票来凑齐金额i,接下来就检查使用这张钞票 x 后还需要多少张钞票                    
        来凑齐剩下的金额 i-x,那么这个数量就存在 dp[i-x] 中,即下面代码的 dp[i-money[j]]
        加1是因为使用了x这张钞票,与当前的dp[i]值进行比较,取两者中的较小值作为新的 f[i] 值
        确保 dp[i] 始终存储凑齐金额 i 所需的最少钞票数 */ 
            dp[i] = min(dp[i], dp[i-money[j]] + 1);
          }
        }
      }
      cout << dp[n] << endl;
    }
    return 0;  
}

浅浅体会一下动态规划的思想就是:

比如想求凑齐金额19,我从金额0开始遍历,凑齐金额1最少需要多少张,凑齐金额5最少需要多少张,假如遍历到了金额5,再在金额5中又依次去遍历不同面值的钞票,保存最少的钞票数;比如

/* 此时金额是5(外循环i=5) 钞票面值是1(内循环j=0, money[j] = 1)

   我要想知道dp[5] 和 dp[4] 哪个小 我就要先知道dp[4]是多少 然后我在之前的外循环里已经

   遍历过了 已经保存了dp[4](凑齐金额4的最小钞票数)*/

 dp[5] = min (dp[5], dp[4] + 1) // min(10e5, 4+1) ==> 5

 dp[4] = min( dp[4], dp[3] + 1) // min(10e5, 3+1) ==> 4

 dp[3] = min( dp[3], dp[2] + 1) // min(10e5, 2+1) ==> 3

 dp[2] = min( dp[2], dp[1] + 1) // min(10e5, 1+1) ==> 2

 dp[1] = min( dp[1], dp[0] + 1) // min(10e5, 0+1) ==> 1

 // 此时金额是5(外循环i=5) 面值是5(内循环j=1, money[j] = 5)

 dp[5] = min( dp[5], dp[0] + 1) // min(5, 1) ==> 1

 这样就是把原问题拆解成一个个子问题 怎么感觉有点像递归

我觉得我应该要去把背包问题给做了,然后专门总结一下,这还挺有意思的好像

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值