二分法补充

前言:二分法一般是对有序数组进行操作,但也可以解决无序数组查找峰值的问题

例:有一个n位数的无序数组,如[5,3,4,2,7,6,9],认为两侧的位置都是无穷小,返回其中一个峰值的下标,0,2,4,6都可

解法:先检查0位置和n-1位置看是不是峰值,若都不是,中间一定会有峰值(左侧上升,右侧下降),看mid是否是峰值,若不是,若mid是下坡,则往左找,若mid是上坡,往右找(找一个就行了)

部分函数代码:

int f(int n){      //a存储数组元素
	if(n==1) return 0;  //0位置是峰值
	if(a[0]>a[1]) return 0;
	if(a[n-1]>a[n-2]) return n-1; //n-1是峰值
	int l=1,r=n-2,ans=-1;
	while(l<=r){
		int mid=(l+r)/2;
		if(a[mid-1]>a[mid]){
			r=mid-1;
		}else if(a[mid]<a[mid+1]){
			l=m+1;
		}else{
			ans=mid;  
			break;
		}
	} 
	return ans;
} 

 三分法是在二分法的基础上提出的,增加了可求取极值的函数的种类(用来确定函数在凹/凸区间上的极值点),下图取自oceanstar的笔记三分法查找详解-优快云博客,由图看出,不论m1,m2如何分布,若m1>m2,则极值点在m1左侧,l=m1+1

若用三分法解决例题(求峰值下标),部分函数代码如下:

int f(int n){
	int l=0,r=n-1;
	while(l<r){
		int midl=l+(r-l)/3,midr=r-(r-l)/3;
		if(a[midl]<a[midr]){       //峰值在midl右边
			l=midl+1;
		}else{
			r=midr-1;
		}
	}
	return l; //或者r,二者相等 
}

01分数规划也是在二分法的基础上,用来求分数的最值

题目:小咪买东西   NC14662

 思路:题目等价于求一组w[],w[i]为0或1,使得

那么应该选vi-x*ci最大的k件物品

代码: 

#include<iostream>
#include<algorithm>
using namespace std;
int n,k;
int c[10010],v[10010];
long long q[10010];
bool check(int x){
	long long s=0;
	for(int i=0;i<n;i++){
		q[i]=v[i]-c[i]*x;
	}
	sort(q,q+n);
	for(int i=n-k;i<n;i++){   //最后k件和 
		s+=q[i];
	}
	return s>=0;
}
int main(){
	int T,i;
	cin>>T; 
	while(T--){
		cin>>n>>k;
		for(i=0;i<n;i++){
			cin>>c[i]>>v[i];
		}
		int l=0,r=1e4,max1=-1;   //max1的范围在(0,10^4)     
		while(l<=r){
			int mid=(l+r)/2;
			if(check(mid)){
				max1=(int)mid;
				l=mid+1;
			}else{
				r=mid-1;
			}
		} 
		cout<<max1<<endl;
	} 
	return 0;
}

END

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值