二分法又称分半法,或对分法,是一种方程式根的近似值求法。二分法经常做为许多算法的优化途径,可以使一些O(n)的算法优化成O(logn)。所以在计算机竞赛中经常使用,为基础算法。
二分法的思想:分而治之。将一个规模为n的问题分解为k个规模较小的子问题,这些子问题互相独立且与原问题相同,(如果子问题的规模仍然不够小,则再划分为k个子问题),然后递归的求解这些子问题,最后用适当的方法将各个子问题的解合并成原问题的解。
1.二分查找
代码:
find_x(a, x)
left = 0, right = a.length - 1
while left <= right
mid = (left + right) / 2
if a[mid] == x
return mid
else if a[mid] < x
left = mid + 1
else
right = mid - 1
return NOT_FOUND
二分法进行数值计算:
对于区间[a,b|上连续不间断且f(a)×f(b)<0的函数y=f(x),一定存在一个零点,也就是存在一个x使得f(x)=0。通过不断地把函数f(x)的零点所在的区间一分为二,使区间的两个端点逐步逼近零点,进而得到零点近似值的方法叫二分法。
代码:
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
const double eps = 1e-3;
double f(double x) {
return pow(x, 4) + 5 * pow(x, 3) + 6 * pow(x, 2) + 7 * x + 4;
}
double cal(double y){
if(f(0)>y||f(100)<y){
return -1;
}double l=0,r=100;
while(r - l > eps){
double mid=(l+r)/2;
if(f(mid)>y){
r=mid;
}else{
l=mid;
}
}
return l;
}
int main () {
double y;
cin>>y;
printf("%.3lf\n",cal(y));
return 0;
}
两种二分快速幂:
package _二分法;
public class _快速幂_1 {
static int mod = (int) 1e9;
static long pow(int a, int b) {
if (b == 0)
return 1 % mod;
long temp = pow(a, b / 2);
if ((b & 1) != 0) {
temp = temp * temp * a % mod;
} else {
temp = temp * temp % mod;
}
return temp;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
long ans=pow(4,6);
System.out.println(ans);
}
}
package _二分法;
public class _快速幂_2 {
//循环写法
// 计算4^6
static int mod = (int) 1e9;
static long pow(int a, int b) {
int res = 1;
while (b != 0) {
if ((b & 1) != 0) {
res = res * a % mod;
}
b >>= 1;
a = a * a % mod;
}
return res;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
long t=pow(4,6);
System.out.println(t);
}
}
二分问题基本是二分的模板加上check函数检查答案。
01分数规划
01分数规划是这样的一类问题,有一堆物品,每一个物品有一个收益ai,一个代价bi,我们要求一个方案,使选择的k个元素一:最大值。
首先我们来一道例题吧,01分数规划的大体方法都是一样的。给出n个物品,每个物品有两个属性a和b,选择k个元素,请问选择k个元素的:最大值是多少?
我们先假设 , 其中xi只有两个取值0,1,表示是否选取第i个物品,并且
,一共选k个元素。
继续假设有一组x在f(x)=v的时候,为最优解,上式变形如下: ,这时候对v二分求解就可以了。
代码如下:
package _二分法;
import java.util.Arrays;
import java.util.Scanner;
public class _01分数规划 {
static int n;
static double eps = 1e-5;
static int[] a;
static int[] b;
static double[] temp;
static double g(double v) {
// 计算ax-v*bx
for (int i = 0; i < n; i++) {
temp[i] = a[i] - v * b[i];
}
Arrays.sort(temp);
double sum = 0;
for (int i = 0; i < n; i++) {
sum += temp[i];
}
return sum;
}
static double cal() {
double l = 0, r = 1e9;
while (r - l > eps) {
double mid = (l + r) / 2;
if (g(mid) > 0) {
l = mid;
} else {
r = mid;
}
}
return l;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
a = new int[n];
b = new int[n];
temp = new double[n];
for (int i = 0; i < n; i++)
a[i] = sc.nextInt();
for (int i = 0; i < n; i++)
b[i] = sc.nextInt();
System.out.println(cal());
}
}