❤️整理的分治算法,供学习算法的同学们学习❤️【建议收藏】

一、认识

二分又分为二分查找和二分答案,它们的时间复杂度为O(二分查找的次数*每次查找的复杂度)。

1.二分查找

二分查找其实就是让你在一大堆数中折半寻找一个数

2.二分答案

二分答案是指折半列举一个答案是否符合题目要求

某一蒟蒻():哎?这咋回事?

另一蒟蒻:来,直接上题来理解

二、学习

1.二分查找

给定一个n,再给n个数和一个要查找的数,输出这个数的下标,用二分查找来实现:

输入:

5
75 324 2 61 23
23

输出:

5

二分一定要记住对半查找

这是无序的一个数组,所以需要先sort排序,而且要输出下标,但是sort排序后计算机无法记住这个数原来在哪,所以要用结构体记录这个数原来的下标,如下:

#include <bits/stdc++.h>
using namespace std;
int n,m;
struct SHU{
	int a,bianhao;
}shu[105];
bool cmp(SHU x,SHU y){
	return x.a<y.a;  //从小到大
}
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>shu[i].a;
		shu[i].bianhao=i;
	}
	cin>>m;
	sort(shu+1,shu+n+1,cmp);
	return 0;
}

如果没学过sort排序,看这篇文章:C++系统函数sort运用https://blog.csdn.net/ljmhxs/article/details/120090253https://blog.csdn.net/ljmhxs/article/details/120090253

这样就排好序了,接下来就是二分查找了(折半查找!):

#include <bits/stdc++.h>
using namespace std;
int n,m;
struct SHU{
	int a,bianhao;
}shu[105];
bool cmp(SHU x,SHU y){
	return x.a<y.a;
}

bool judge(int x){
	return shu[x].a > m;  //看不懂可以看下面 
}

/*
bool judge(int x){
	if(shu[x].a > m) return 1;  //如果中间数比 m 大,返回1 
	else return 0;
}
*/

int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>shu[i].a;
		shu[i].bianhao=i;
	}
	cin>>m;
	sort(shu+1,shu+n+1,cmp);
	
	int l=1,r=n,mid;  // l 指左边,r 指右边,mid 指中间 
	while(l<r){
		mid=(l+r)/2;  //折半,看中间与要找的数 m 的关系 
		if(judge(mid)){  //判断关系 
			l=mid+1;  //如果发现中间比要找的数大了 ,那就在右边找 
		}else{
			r=mid;  //否则往左边找 
		}
	}
	cout<<shu[mid].bianhao;  //输出编号即可 
	return 0;
}

这就是二分查找

2.二分答案

一个整数n和一个整数k,给出n个树的高度,要求找出一个高度,使得这n个数的高度减去这个高度的结果正好为k.

输入

5 100
90 95 60 70 85

输出

60

二分答案一定要对半找

某杠精:总感觉这句话在哪里见过?

某作者:我感觉你感觉的没错!

这句话是极为重要的!!学习二分一定要记住!

 二分首先要找到查找的边界值,这道题的边界值是这些树的最高的和最低的,所以输入为:

(边界值其实怎样都可以,比如这道题,也可以是1和1000,不影响真正结果,只要右边界比答案大就可以了)

#include <bits/stdc++.h>
using namespace std;
int n,k,a[1000005],maxx,minn;
int  main(){
	cin>>n>>k;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		maxx=max(maxx,a[i]);  //最大
		minn=min(minn,a[i]);  //最小
	}

	int l=minn,r=maxx,mid;
	while(l<=r){
		mid=(l+r)>>1;  //相等于mid=(l+r)/2;
		
	}
        //二分

	return 0;
}

接下来就是二分答案,折半列举答案后看此答案是否符合题意:(看代码!)

#include <bits/stdc++.h>
using namespace std;
int n,k,a[1000005],maxx,minn;

int judge(int x){  //3种情况返回值类型为int
	int sum=0;  //累加器
	for(int i=1;i<=n;i++)
		if(a[i]-x>=0)  //防止累加到负数,影响最终结果
			sum+=a[i]-x;  //累加 减去折半查找到的答案
	if(sum>k) return 1;  //累加后比k大,返回1
	else if(sum==k) return 0;   //累加后正好等于,返回0,回去输出
	else if(sum<k) return 2;  //累加后小于k,返回1
}

int  main(){
	cin>>n>>k;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		maxx=max(maxx,a[i]);
		minn=min(minn,a[i]);
	}
        //输入
        
	int l=minn,r=maxx,mid;
	while(l<=r){
		mid=(l+r)>>1;
		int f=judge(mid);
		if(f==1){  //累加后比k大
			if(judge(mid+1)==2){  //如果没有正好的答案,只有超出一点的
                                              //检查答案+1是否比k小,如果小的话
				cout<<mid;  //输出答案
				return 0;
			}
			l=mid-1;  //左边界找右边,一定要-1,因为要把mid包括进去算
		}else if(f==0){
			cout<<mid;  //正好就直接输出
			return 0;
		}else if(f==2){  //累加后比k小
			r=mid+1;  //右边界找左边,一定要+1,因为要把mid包括进去算
		}
	}
	cout<<mid;
        //二分答案
	
        return 0;
}

所以你似乎掌握了亿点二分的知识呢!还是不会的同学还是得多刷题

such as(题解什么的自己找)

A-B 数对https://www.luogu.com.cn/problem/P1102https://www.luogu.com.cn/problem/P1102

 眼红的Medusahttps://www.luogu.com.cn/problem/P1571https://www.luogu.com.cn/problem/P1571

[NOIP2001 提高组] 一元三次方程求解https://www.luogu.com.cn/problem/P1024https://www.luogu.com.cn/problem/P1024

进击的奶牛https://www.luogu.com.cn/problem/P1824https://www.luogu.com.cn/problem/P1824

木材加工https://www.luogu.com.cn/problem/P2440https://www.luogu.com.cn/problem/P2440

[NOIP2015 提高组] 跳石头https://www.luogu.com.cn/problem/P2678https://www.luogu.com.cn/problem/P2678

【例7.4】 循环比赛日程表http://ybt.ssoier.cn:8088/problem_show.php?pid=1325icon-default.png?t=L892http://ybt.ssoier.cn:8088/problem_show.php?pid=1325网线主管http://ybt.ssoier.cn:8088/problem_show.php?pid=1242icon-default.png?t=L892http://ybt.ssoier.cn:8088/problem_show.php?pid=1242
查找最接近的元素http://ybt.ssoier.cn:8088/problem_show.php?pid=1240icon-default.png?t=L892http://ybt.ssoier.cn:8088/problem_show.php?pid=1240

月度开销http://ybt.ssoier.cn:8088/problem_show.php?pid=1243icon-default.png?t=L892http://ybt.ssoier.cn:8088/problem_show.php?pid=1243

强烈建议做做这些题!

不会的同学私信我!

点赞你要亮,关注干得漂亮

不关注点赞你就别走(好像我也留不住)

那就要个点赞吧(要求不大吧)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值