IT评测·应用市场-qidao123.com技术社区
标题:
算法:二分讲解
[打印本页]
作者:
欢乐狗
时间:
2024-10-29 00:22
标题:
算法:二分讲解
二分的基本认识:
#include<bits/stdc++.h>
using namespace std;
//二分法 有序的序列找东西 left right
/*
1~100的数字
mid=(left+right)/2;
right=mid-1;
left=mid+1;
while(left<=right)
while(left<=right){
mid=(left+right)/2
if(mid==ans) return 0;
else if(mid>ans) right=mid-1;
else if(mid<ans) left=mid+1;
}
1.二分数字 2.二分数组下标
2.小数二分
*/
double a;
int main(){
cin>>a;
double l=0,r=a,mid;
while(r-l>=0.0001){ //l<=r r-l>=0 整数的
mid=(l+r)/2;
if(mid*mid==a){
printf("%.3lf",mid);
return 0;
}else if(mid*mid>a){
r=mid; //不进行 r=mid-0.0001;
}else{
l=mid;
}
}
printf("%.3lf %.3lf",l,r);
return 0;
}
复制代码
#include<iostream>
#include<cstdio>
using namespace std;
//二分的停止为 left<=right
//每次要获取一个 mid=(left+right)/2
//小了 变left = mid + 1
//大了 变right= mid - 1
int k;
int main(){
cin>>k;
//要求猜的数字就是k
//left right 是用于确定猜数字的范围
int left=1,right=100,mid,cnt=0;
while(left<=right){
//获取一个中间值
mid=(left+right)/2;
cnt++;//次数增加
//判断大了还是小了
if(mid>k){ //大了
right=mid-1;
} else if(mid<k){
left=mid+1;
}else{ //等于
cout<<cnt;
return 0;
}
}
return 0;
}
复制代码
二分基础练习:
(1)二分正常练习
(1)AC题解:
#include<bits/stdc++.h>
using namespace std;
int ans,n,a[10005];
int main(){
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
cin>>ans;
int left=1,right=n,mid;
while(right>=left){
mid=(left+right)/2; //下标
if(a[mid]>ans){
right=mid-1;
}else if(a[mid]<ans){
left=mid+1;
}else{
cout<<mid; //答案下标
return 0;
}
}
cout<<-1;
return 0;
}
复制代码
(2) 标题:
要求输入一个整数
求这个整数开立方根的结果保留5位小数
例如:
输入:27
输出:3.00000
输入:5
输出:1.70998
复制代码
(2)AC题解:
#include<bits/stdc++.h>
using namespace std;
double n;
int main(){
cin>>n;
double left=0,right=n,mid;
while(right-left>=0.0000001){
mid=(right+left)/2;
if(mid*mid*mid>n){
right=mid;
}else if(mid*mid*mid<n){
left=mid;
}else{
printf("%.5lf",mid);
return 0;
}
}
printf("%.5lf",mid);
return 0;
}
复制代码
(3)练习题
(3)AC题解:
#include<iostream>
#include<cstdio>
using namespace std;
int a[1000005],n,m,x;
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=m;i++){
cin>>x;//x就是要查找的数据
int left=1,right=n,mid,ans=-1;
while(left<=right){
// mid=(right+left)/2;
mid=(right-left)/2+left;
if(a[mid]>=x){ //a[mid] 还要继续缩短范围
right=mid-1;
}else{
left=mid+1;
}
if(a[left]==x){ //真正的答案是放在最左边的
ans=left;
break;
}
}
cout<<ans<<" ";
}
return 0;
}
复制代码
(4)练习题
(4)AC题解:
#include<bits/stdc++.h>
using namespace std;
long long a[200005],n,c,ans;
int main(){
cin>>n>>c;
for(int i=1;i<=n;i++) cin>>a[i];
sort(a+1,a+n+1);
for(int i=1;i<=n;i++){
long long A=c+a[i];//要查找的内容
int ansl,ansr;
//是A的最左边的
int left=1,right=n,mid;//下标
while(left<=right){
mid=(left+right)/2;
if(a[mid]>=A) right=mid-1;
else left=mid+1;
}
ansl=left;
//是A的最右边的
left=1,right=n;//下标
while(left<=right){
mid=(left+right)/2;
if(a[mid]>A) right=mid-1;
else left=mid+1;
}
ansr=right;
ans+=ansr-ansl+1;
}
cout<<ans;
return 0;
}
复制代码
拓展 :
lower_bound()和upper_bound().
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
/*
lower_bound() //第一个不小于查找的元素的下标
upper_bound() //第一个大于查找元素的下标
*/
int a[12]={1,3,3,3,5,7,9,11,13,15,15};
int main(){
//1,3, 6 sort(a+1,a+n+1)
cout<<lower_bound(a,a+11,6)-a<<endl; //logn
cout<<upper_bound(a,a+11,3)-a<<endl;
if(a[lower_bound(a,a+11,6)-a]==ans) cout<<lower_bound(a,a+11,6)-a;
else cout<<-1;
return 0;
}
复制代码
小数的二分 :
#include<iostream>
#include<cstdio>
using namespace std;
//小数二分的特点 误差 精确值 我们需要通过精确值来写循环的判断
double k;
int main(){
cin>>k;
double left=0,right=k,mid;
while(right-left>=0.0001){ //0.0001 是因为精确值是0.001
mid=(right+left)/2;
if(mid*mid>k){
right=mid;
}else if(mid*mid<k){
left=mid;
}else{
// cout<<mid; //用于整数
printf("%.3lf",mid);
return 0;
}
}
printf("%.3lf",mid);
// cout<<mid;
return 0;
}
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
欢迎光临 IT评测·应用市场-qidao123.com技术社区 (https://dis.qidao123.com/)
Powered by Discuz! X3.4