分治法:不光是查找值!“二分搜索” (未完成)

二分搜索法:是通过不断缩小解可能存在的范围,从而求得问题最优解的方法。在程序设计竞赛或者刷题网站上,我们常常会见到,二分搜索法和其他算法结合的题目。

常见的二分搜索代码:

int MyBinarySearch(const vector<int> &ivec, int val){
	if(ivec.size()==0) return -1;
	auto beg = ivec.begin(),end = ivec.end()-1;
	while(beg<=end){
		auto mid =beg;
		std::advance(mid,std::distance(beg,end));
		if(*mid == val) return std::distance(ivec.begin(),mid);
		else if(*mid > val) end = mid-1;
		else if(*mid < val) beg = mid+1;
	}
	return -1;
}

二分查找易错点:链接

下面我们来看几道二分搜索法的问题。

1. 从有序数组中查找某个值( lower_bound )

题述:
给定长度为 n 的单调不下降数列 a0,------an-1 和一个数 k,求满足 ai>=k 条件的最小的 i。不存在的情况下输出 n。

限制条件:

  • 1 <= n <= 10^6
  • 0 <= a0<=a1-------<=an-1 <10^9
  • 0 <= k <=10^9

题解:

  • 我们要以 ( ] 半包围来求解 不小于的第一个元素问题
  • 循环条件为l 和 r之间的位置大于1,这样保证 r 取到的右游标为准确的目标角标
  • 如果中间值 大于等于 目标值,那么使用右 游标,缩小二分查找范围
  • 中间值如果小于目标值,使用左游标,缩小二分查找范围,
int Mylower_bound(const vector<int>& ivec,const int &k){
	int l=-1,r=ivec.size()-1;
	while(r-l>1){
		auto mid = (l+r)>>1;
		if(ivec.at(mid) >= k) r=mid;
		else l=mid;
	}
	return r;
}
int Myupper_bound(const vector<int>& ivec,const int &val){
	int l=-1,r=ivec.size()-1;
	while(r-l >1){
		auto mid = (l+r)>>1;
		if(ivec.at(mid) > val) r=mid;
		else l = mid;
	}
	return r;
}

STL Lower_bound 代码:

 template<typename _ForwardIterator, typename _Tp, typename _Compare>
    _ForwardIterator
    __lower_bound(_ForwardIterator __first, _ForwardIterator __last,
		  const _Tp& __val, _Compare __comp)
    {
      typedef typename iterator_traits<_ForwardIterator>::difference_type
	_DistanceType;

      _DistanceType __len = std::distance(__first, __last);

      while (__len > 0)
	{
	  _DistanceType __half = __len >> 1;
	  _ForwardIterator __middle = __first;
	  std::advance(__middle, __half);
	  if (__comp(__middle, __val))
	    {
	      __first = __middle;
	      ++__first;
	      __len = __len - __half - 1;
	    }
	  else
	    __len = __half;
	}
      return __first;
    }

2. 假定一个解并判断是否可行( Cable master POJ:No. 1064)

题述:有N条绳子 ,他们的长度分别为 Li 。如果从他们中切割出 K 条长度相同的绳子的话,每条绳子每条最长能有多长 ?答案保留到小数点后 2 位。

限制条件:

  • 1 <= N <= 10000
  • 1 <= K <= 10000
  • 1 <= Li <= 100000

输入: N=4 K=11 L={8.02 , 7.43 , 4.57, 5.39}
输出: 2.00(每条绳子可以分成 4 条,3条,2条,2条)共计11条

题解: 我们套用二分搜索的模型得出问题。 令:

条件 C(x):= 可以得到 K 条长度为 x 的绳子

之后该问题就变成了求最大的 x 值的问题。

思路解释;:使用边界法表示 x 的边界,每一次通过判断 该 使用 x 求得的绳子个数缩进边界,大概循环100次就能达到想要的数值,之后取小数点后两位即可。

bool SatisfyAmount(double x,const vector<double>& dvec,const int desCount){
	int amount = 0;
	for (decltype(dvec.size()) i = 0; i !=dvec.size(); ++i) {
		amount += (int)(dvec.at(i)/x);
	}
	return amount>=desCount;
}

double MaxInterceptLength(const vector<double>& dvec,const int desCount){
	double l=0,r=INT64_MAX;
	for (int i = 0; i !=100; ++i) {
		double mid = l+(r-l)/2;
		if(SatisfyAmount(mid,dvec,desCount)) l = mid;
		else r = mid;
	}
	return floor(r*100)/100;
}

3. 最大化最小值 (Aggressive cows POJ No.2456)

题述: 农夫约翰搭了一间有 N 间牛舍的小屋。 牛舍排在一条线上, 第 i 号牛舍在 xi 的位置。 但是他的 M 头牛对小屋很不满意,因此互相攻击 。 约翰为了防止牛之间相互伤害, 因此把每头牛都放在离其他牛尽可能远的牛舍。 也就是要最大化最近的两头牛之间的距离。

样例:

输入 N=5,M=3,x={1,2,8,4,9}

猜你喜欢

转载自blog.csdn.net/chongzi_daima/article/details/104592139
今日推荐