二分法应用

一、最大化最小值

eg:poj 2456:疯牛

#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn = 1e7 + 10;
ll a[maxn];
ll n, c;
//对距离进行二分
int ans = 0;
int sum = 1;
int main()
{
	cin >> n >> c;
	for (int i = 1; i <= n; i++)
		cin >> a[i];
	sort(a + 1, a + 1 + n);
	int l = 1;
	int r = a[n];
	ll mid = (l + r) / 2;
	int sum;
	int st;
	int en;
	while (r - l > 1)
	{
		sum = 1;
		st = 1;
		en = 2;
		while (en <= n)
		{
			if (a[en] - a[st] >= mid) {
				st = en;
				sum++;
			}
			en++;
		}
		if (sum >= c) {
			l = mid;
			mid = (l + r) / 2;
		}
		else {
			r = mid;
			mid = (l + r) / 2;
		}
	}
	ans = mid;
	cout << ans << endl;
	return 0;
}

二、最大化平均值

eg:有n个物品的重量和价值分别是wi和vi,从中选出k个物品使得单位重量价值最大。

样例(wi,vi)=(2,2) (5,2) (2,1)

解析:

这道题不能通过比较单位重量价值去计算,要利用二分思想。

设C(x)为单位重量的价值,满足C(x)>=x,如果x最大,则C(x)也必然最大,所以我们要做的是利用二分方法找到最大的x。

设w······wj是我们要找的那k个物品,则:

C(x)=(wi+···+wj)/(vi+···+vj)>=x

->wi+···+wj>=(vi+···+vj)*x

->wi+···+wj>=vi*x+···+vj*x

->(wi-vi*x)+···+(wj-vj*x)>=0

所以我们只要在0~INF内寻找满足上式合法的x,并且令x最大即可。

由于这是一个线性函数,所以利用二分去寻找最大的x。

三、尺取(二分特例)

eg:有一个长度为n的数列,一正整数S,求出一个长度最小的连续子序列,使它们的和>=S

样例:n=10,S=15;

           a={5 1 3 5 10 7 4 9 2 8};

解析:定义一个sum=0,然后从左向右加,如果sum>S,则从左侧减,如果减完后发现sum<15,则从右侧加。

实现过程:sum=0   a[]=5 1 3 10 7 4 9 2 8   S=15

5

->右加 5 1                          sum<15

->右加 5 1 3                       sum<15

->右加 5 1 3 5                    sum<15

->右加 5 ,1, 3, 5, 10           sum>15

->左减     1, 3, 5, 10           sum>15

->左减     3, 5, 10                ·······

->左减         5, 10

->左减             10

->右加             10, 7

->左减                   7

->右加                   7, 4

->右加                   7, 4, 9

->左减                       4, 9

``````

综上:只要sum>15就从左侧减,否则从右侧加

待更新······

猜你喜欢

转载自blog.csdn.net/zsnowwolfy/article/details/81232862