course3 二分

这周的课程是二分,一听到二分,我就会想起二分查找,其实二分的思想在许多的数据结构中都有广泛的用处,那今天的二分呢,实际上实际上是一种解题的策略:

“二分答案”,也就是说,如果一道题目的答案落在某一个区间中,如果某个答案在验证正确性以后,可以确定该答案以后或以前的数值都不是最优时,就可以使用该方法了。

POJ 1064 N条线,从中切K条长度相等的线,求最长可多长?

答案可定在(0, maxlen]之中, 如果其中的x经检验可行,那(0,x)就一定不是最优解。满足二分答案的思路

1.注意如何保留2位小数               2.mid为0时不能做除数      3.left <= right

#include <cstdio>
#include <cmath>

const int maxn = 10000 + 5;
double small = 0.00000001;
int N, K;
int n[maxn];
int left, right,tmp, mid;
double enter;

int main()
{
	scanf("%d %d", &N, &K);
	for (int i = 0; i < N; i++) {
		scanf("%lf", &enter);
		n[i] = int((enter+small) * 100);
		if (n[i] > right) right = n[i];
	}
	while(left <= right) {
		mid = (left + right) / 2;
		if (mid == 0) {
			left = mid+1;
			continue;
		}
		int count1 = 0;
		for (int i = 0; i < N; i++) {
			count1 += n[i] / mid;
		}
		if (count1 >= K) left = mid+1;
		else right = mid-1;
	}
	printf("%.2f\n", right/100.0);	
}


最大化最小值:同样满足二分的策略,取值落在一个区间,检测完一个值的可行性后就可以砍掉一半的区间, 那么那点在于如何对一个点进行检测对错

POJ2456 : 给出N个点,选C个位置令个点的最小距离最大。

keypoint:如何检测某点是否可行,sort后,从a[0]出发不断+d,看有几个。

#include <cstdio>
#include <algorithm>
using namespace std;

const int maxn = 100000 + 5;
int N, C, left, right, mid;
int a[maxn];

bool test(int n) {
	int counter = 1;
	int last = a[0];
	for (int i = 1; i < N; i++) {
		if (last + n <= a[i]) {
			counter++;
			last = a[i];
		}
	}
	if (counter >= C) return true;
	else return false;
}

int main()
{
	scanf("%d%d", &N, &C);
	for (int i = 0; i < N; i++) {
		scanf("%d", &a[i]);
	}
	sort(a, a+N);
	left = 1; right = a[N-1] - a[0];
	while (left <= right) {
		int mid = (left + right) / 2;
		if (test(mid)) left = mid + 1;
		else right = mid - 1;
	}
	printf("%d\n", right);
}



三分法: 用于求单峰函数的极值,基于这么一个事实:

当 value(m1) > value(m2) 时 就可以将 m2 - right 砍掉, 虽然每次去掉1/3, 比二分少一点,但效率依旧好

ZOJ3203

#include <iostream>
#include <cstdio>
using namespace std;

#define eps 1e-8
double Left, Right, mid, dmid;
double midvalue, dmidvalue;
int cases;
double h, H, D, dx;

double calcu(double x)
{
	if (x >= dx) return h*(D-x) / (H - h);
	else return (h * D - H * x) / (D - x) + x;
}

void solve() 
{
	while (Left + eps < Right) {
		mid = (Left * 2 + Right) / 3;
		dmid = (Left + Right * 2) / 3;
		midvalue = calcu(mid);
		dmidvalue = calcu(dmid);
		if (midvalue >= dmidvalue) Right = dmid;
		else Left = mid;
	}
}

int main()
{
	cin >> cases;
	while (cases--) {
		scanf("%lf%lf%lf", &H, &h, &D);
		dx = h * D / H;
		Left = 0.0; 
		Right = D;
		solve();
		printf("%.3lf\n", calcu(Left));
	}
}

	



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值