二分
先把昨天解决的二分问题给写了,就是前几天那个寻找食物储量的问题
#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;
}
注意区间和边界值
继续写完,昨天就写了一道题。。。。果然还是不能拖 今日事今日毕 明日复明日 明日何其多啊!
这是一道以前有一次没有搞定的题目,当时用的是模拟,样例也能通过,但是答案只能过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
这样就是把原问题拆解成一个个子问题 怎么感觉有点像递归
我觉得我应该要去把背包问题给做了,然后专门总结一下,这还挺有意思的好像