二分查找
二分就是求一个区间的值,通过二分来使他更快的找到,取左右两边的数,使满足条件后令其中值等于左值(右值)(具体看情况)然后当满足条件(l+1<r)时跳出(有特殊情况是在l<r时跳出,如:l=m+1时,因为值在增加,所以不用l+1<r)。
题目如下:
铺公路
B市和T市之间有一条长长的高速公路,这条公路的某些地方设有路标,但是大家都感觉路标设得太少了,相邻两个路标之间往往隔着相当长的一段距离。为了便于研究这个问题,我们把公路上相邻路标的最大距离定义为该公路的“空旷指数”。
题目描述
现在政府决定在公路上增设一些路标,使得公路的“空旷指数”最小。他们请求你设计一个程序计算能达到的最小值是多少。请注意,公路的起点和终点保证已设有路标,公路的长度为整数,并且原有路标和新设路标都必须距起点整数个单位距离。
输入格式
第1行包括三个数L、N、K,分别表示公路的长度,原有路标的数量,以及最多可增设的路标数量。
第2行包括递增排列的N个整数,分别表示原有的N个路标的位置。路标的位置用距起点的距离表示,且一定位于区间[0,L]内。
输出格式
输出1行,包含一个整数,表示增设路标后能达到的最小“空旷指数”值。
输入
101 2 1
0 101
输出
51
代码如下:(这里是l<r的代码)
#include<bits/stdc++.h>
#define bug(a) (cout<<"*"<<a<<endl)
#define bugg(a,b) (cout<<"*"<<a<<' '<<b<<endl)
#define buggg(a,b,c) (cout<<"*"<<a<<' '<<b<<' '<<c<<endl)
#define endl '\n'
#define MAX 0x3f3f3f
using namespace std;
typedef long long ll;
ll a[100005],n,m,s;
bool juge(ll k) {
int ans = 0;
for (int i = 1; i < n; i++) {
ans += (a[i + 1] - a[i])/k;
if ((a[i + 1] - a[i]) % k == 0)ans--;
}
if (ans > s)return 0;
else return 1;
}
int main()
{
ll i,j,l=0,r,mid;
cin >> m>>n>>s;
for (i = 1; i <= n; i++) {
cin >> a[i];
}
r = m;
while (l < r) {
mid = (l + r) / 2;
if (!juge(mid))l = mid+1;
else r = mid;
//bugg(l, r);
}
cout << l << endl;
}
下面是l+1<r的代码
题目如下:
伐木工
伐木工人米尔科需要砍倒M米长的木材。这是一个对米尔科来说很容易的工作,因为他有一个漂亮的新伐木机,可以像野火一样砍倒森林。不过,米尔科只被允许砍倒单行树木。
米尔科的伐木机工作过程如下:米尔科设置一个高度参数H(米),伐木机升起一个巨大的锯片到高度H,并锯掉所有的树比H高的部分(当然,树木不高于H米的部分保持不变)。米尔科就行到树木被锯下的部分。
例如,如果一行树的高度分别为20,15,10和17,米尔科把锯片升到15米的高度,切割后树木剩下的高度将是15,15,10和15,而米尔科将从第1棵树得到5米,从第4棵树得到2米,共得到7米木材。
米尔科非常关注生态保护,所以他不会砍掉过多的木材。这正是他为什么尽可能高地设定伐木机锯片的原因。帮助米尔科找到伐木机锯片的最大的整数高度H,使得他能得到木材至少为M米。换句话说,如果再升高1米,则他将得不到M米木材。
输入格式
第1行:2个整数N和M,N表示树木的数量(1<=N<=1000000),M表示需要的木材总长度(1<=M<=2000000000)
第2行:N个整数表示每棵树的高度,值均不超过1000000000。所有木材长度之和大于M,因此必有解。
输出格式
第1行:1个整数,表示砍树的最高高度。
输入
5 20
4 42 40 26 46
输出
36
代码如下:
#include<bits/stdc++.h>
#define bug(a) (cout<<"*"<<a<<endl)
#define bugg(a,b) (cout<<"*"<<a<<' '<<b<<endl)
#define buggg(a,b,c) (cout<<"*"<<a<<' '<<b<<' '<<c<<endl)
#define endl '\n'
#define MAX 0x3f3f3f
using namespace std;
typedef long long ll;
const int M = 1000000 + 10;
ll arr[M], n, m;
bool juge(int num) {
ll nu = 0;
for (ll i = 1; i <= n; i++) {
if (arr[i] > num)
nu += arr[i] - num;
else continue;
}
//bugg(num, nu);
if (nu < m)return 1;
else return 0;
}
int main()
{
ll i, j,ma=0;
cin >> n >> m;
for (i = 1; i <= n; i++) {
cin >> arr[i];
ma = max(arr[i], ma);
}
ll l = 0, r = ma+1;
while (l + 1 < r) {
ll mid = (l + r) / 2;
if (juge(mid)) {
r= mid;
}
else l = mid;
}
cout << l << endl;
}
还有种写法;
while(l<=r)
{
mid=(l+r)/2;
if(条件满足)l=mid+1;
else r=mid-1;
}
方程组求解
题目;方程组求解(洛谷)
这道题题目复制出来太难看就直接给网站了
求区间内精度为多少多少时的解
这里可以不用一直使用判断某个中值的正确性来将其赋值给左值还是右值。
while (r - l >= 0.001)//时期精确到小数点后两位,因为都到第三位了所以
{//输出的时候输出左值还是右值是没区别的
m = (r + l) / 2;
if (sum(r) * sum(m) <= 0) {//这里是判断条件
l = m;//判断他是否满足两个点的值相乘是否小于0
}//小于则返回l等于中值
else r = m;//反之则返回右值
}
上面的代码一开始求中值与右值的区间值是否小于0,小于则返回l=r
为啥要这样呢?
哎,问得好,因为函数的性质两个点的值相乘小于0中间必含有一个根,这道题就是要咱求根的;
完整代码如下:
#include<iostream>
#include<cstdio>
using namespace std;
double a, b, c, d;
double sum(double x) {
return a * x * x * x + b * x * x + c * x + d;
}
int main()
{
int cont = 0;
cin >> a >> b >> c >> d;
for (int i = -100; i < 100; i++) {
double l = i;
double r = i + 1;
double m;
if (!sum(l))//如果左值等于0可以直接输出
{
printf("%.2lf ", l);
cont++;
}
if (sum(l) * sum(r) < 0)
{
while (r - l >= 0.001)
{
m = (r + l) / 2;
if (sum(r) * sum(m) <= 0) {
l = m;
}
else r = m;
}
printf("%.2lf ", l);
cont++;
}
if (cont >= 3)break;//当满足三个解的时候跳出循环
}
}
给个经验
如果是求最小的最大,那么令等于号放在l=mid那里
如果是求最大的最小,令等于号放在r=mid那里