二分答案(超级详细)

要说二分答案,首先要从二分说起,首先先上题:

8ec40c30933d42608f6484f1456859f3.jpeg

 题目简单的来讲,就是有一个由小到大的数列,从中搜索一个数的下标,我们先来看一下二分的模板:

while(start<end){
    mid=start+(end-start)/2;
	if(num[mid]>=s){ //这里的s就是我们要搜索的数
		end=mid;
	}else{
		start=mid+1;
	}
}

就是我们从这个数列的中间这个数开始比较,是中间这个数大还是我们要找的这个数大

那么现在就有三种情况:

中间的数=要找的数向数列的左边搜索,因为要找到第一次出现这个数的下标
中间的数>要找的数向数列左边搜索
中间的数<要找的数向数列右边搜索

这个时候我们不断去重复上述操作:

我们用start来存储这个数列开始的坐标,end来存储这个数列结束的坐标,mid来存储这个数列中间这个数的坐标。

注意:找mid的值我们最好使用start+(end-start)/2而不是(start+end)/2,因为假如这个数列很大,start+end有可能直接爆了。

那么最后我们就可以找到这个数的下标了,我们要这个数的下标如果简单的遍历,那么时间复杂度就是O(nm),用二分就可以把时间缩短到O(nlogm)

接下来就是程序完整代码:

#include<bits/stdc++.h>
using namespace std;
int num[1000005],m,n;
int check(int s){
	int start=1,end=m,mid=0;
	while(start<end){
		mid=start+(end-start)/2;
		if(num[mid]>=s){
			end=mid;
		}else{
			start=mid+1;
		}
	}
	if(num[start]==s){
		return start;
	}else{
		return -1;
	}
}
int main(){
	cin>>m>>n;
	int t=0;
	for(int i=1;i<=m;i++){
		cin>>num[i];
	}
	for(int i=1;i<=n;i++){
		cin>>t;
		cout<<check(t)<<' ';
	}
	return 0;
}

那么接下来,我们在知道了二分搜索的前提下,我们来看一看二分答案,二分答案的实质就是把前面二分搜索的数列变为我们答案的所有可能性,mid就是我们尝试的答案,二分答案的前题就是答案具有单调性,直接将有点难以理解,还是直接上题:

565f1bf3aa284028966222fd2c1de9af.jpeg

首先是看一下题目,是符合单调性的,然后这些长度都是两位小数,非常不方便我们二分,这边就把所有的长度都*100,最后把答案再/100,就可以避免了。

我们这里假设,绳子最长是题目里给的100000.00,*100后就是10000000,这就是答案的最大值,不可能会比这个大,那么答案的最小值就是0,所以start=0,end=10000000,所以我们这里把这个数组开始二分,那么现在的难点就是验证这个答案能不能取到。

我们现在用每一个长度去除以mid,把每一个段数加起来,然后把这个总段数和我们要的段数K进行比较,我们假设这个总段数为num,结论如下:

num>K向右搜索
num=K向右搜索
num<K向左搜索

向右搜索,我们就把start=mid

向左搜索,我们就把end=mid

然后不断收缩,这个mid/100就是最终的答案,直接上代码:

#include<bits/stdc++.h>
using namespace std;
double num;
double a[1000005];
double check(int s,int s1){
	int all=0;
	for(int i=0;i<num;i++){
		all+=(a[i]/s);
	}
	if(all>=s1){
		return 1;
	}else{
		return 0;
	}
} 
int main(){
	double s;
	cin>>num>>s;
	long long end=10000000000,start=1,mid=0,ans=0;
	for(int i=0;i<num;i++){
		cin>>a[i];
		a[i]=a[i]*100;
	}
	while(start<=end){
		mid=(int)(start+end)/2;
		if(check(mid,s)){
			start=mid+1;
			ans=mid;
		}else{
			end=mid-1;
		}
	}
	printf("%.2lf",(double)ans/100);
	return 0;
}

  • 23
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
二分查找和二分答案是两个不同的概念。 二分查找(Binary Search)是一种常用的查找算法,适用于有序的数组或列表。它通过将目标值与数组中间元素进行比较,从而确定目标值在数组的左半部分还是右半部分,然后再在相应的半部分中继续查找,直到找到目标值或者确定目标值不存在。二分查找的时间复杂度是 O(logn)。 以下是一个简单的 C++ 实现示例: ```cpp int binarySearch(int arr[], int target, int left, int right) { while (left <= right) { int mid = left + (right - left) / 2; if (arr[mid] == target) return mid; else if (arr[mid] < target) left = mid + 1; else right = mid - 1; } return -1; // 目标值不存在 } ``` 二分答案(Binary Search for Answer)是一种在某个范围内寻找满足某个条件的最优解的方法。它通过在一个给定范围内进行二分搜索,每次确定一个中间值,然后判断该中间值是否满足条件。如果满足条件,则将搜索范围缩小到左半部分;如果不满足条件,则将搜索范围缩小到右半部分。通过不断缩小搜索范围,最终找到满足条件的最优解。 这种方法在一些问题中很常见,比如在一个有序数组中找到满足某个条件的最小/最大值,或者确定一个函数的最大/最小值等。 具体的实现方式会根据具体的问题而有所不同,但基本的思路是相似的。你可以根据具体的问题来实现相应的二分答案算法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值