course3 二分

来源:互联网 发布:北京110网络报警平台 编辑:程序博客网 时间:2024/06/05 07:14

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

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

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-8double 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));}}



0 0
原创粉丝点击