二分

二分法

对一个有序数组:例如 1 2 3 4 5 进行元素查找时,例如查找元素5,如果从头遍历到底,时间复杂度为O(n),但是如果用二分搜索的方法
首先去最中间的值3,3比5小,所以搜索区间移动到[4 5]内,这样一下子就将范围缩小了一半,然后这样一直进行下去直至找到,或者是l>r即为未找到,程序结束

package fir;
public class Main{
    public void main(String[] args){
        int arr[]={1,2,3,4,5};
        int l,r,mid;
        l=0;
        r=4;
        int n=5;
        while(l<=r){
            mid=(l+r)/2;
            if(arr[mid]>n){
                l=mid+1;
            }
            else if(arr[mid]==n){
                break;
            }
            else r=mid-1;
        }
    }
}

如果你以为二分就这点应用就太low了
二分的进阶应用
题目描述:
Dr.Kong设计的机器人卡多非常爱玩,它常常偷偷跑出实验室,在某个游乐场玩之不疲。这天卡多又跑出来了,在SJTL游乐场玩个不停,坐完碰碰车,又玩滑滑梯,这时卡多又走入一个迷宫。整个迷宫是用一个N * N的方阵给出,方阵中单元格中填充了一个整数,表示走到这个位置的难度。

这个迷宫可以向上走,向下走,向右走,向左走,但是不能穿越对角线。走迷宫的取胜规则很有意思,看谁能更快地找到一条路径,其路径上单元格最大难度值与最小难度值之差是最小的。当然了,或许这样的路径不是最短路径。

机器人卡多现在在迷宫的左上角(第一行,第一列)而出口在迷宫的右下角(第N行,第N列)。

卡多很聪明,很快就找到了这样的一条路径。你能找到吗?
输入描述:
第一行: N 表示迷宫是N*N方阵 (2≤ N≤ 100)

接下来有N行, 每一行包含N个整数,用来表示每个单元格中难度 (0≤任意难度≤120)。
输出描述:
输出为一个整数,表示路径上最高难度与和最低难度的差。
样例输入:
5
1 1 3 6 8
1 2 2 5 5
4 4 0 3 3
8 0 2 3 4
4 3 0 2 1
样例输出:
2
这道题就是一个深度优先搜索问题,但是如果直接深搜每一种情况一定会超时,不如换个想法,我们来枚举难度差,既然是求最小的难度差,我们对难度区间[0,120]遍历,用二分法遍历,首先如果mid=(l+r)/2的难度范围内能满足条件,就不必再遍历[mid,r],如果不能满足条件,就不必遍历[l,mid];因此我们可以用二分的方法缩小遍历的范围,对不必要遍历的难度区间舍去,减少遍历次数,减少时间消耗。

#include<iostream>
#include<cstring>
using namespace std;
int dx[]={0,0,1,-1};
int dy[]={-1,1,0,0};
int map[101][101];
int v[101][101];
bool flag;
int mmax,mmin;
int n;
int l,r,mid;
void dfs(int x,int y){
	v[x][y]=1;
	if(flag)return ;
	if(map[x][y]>mmax||map[x][y]<mmin){
		return;
	}
	if(x==n-1&&y==n-1){
		flag=true;
		return;
	}
	for(int i=0;i<4;i++){
		if(x+dx[i]<=n-1&&x+dx[i]>=0&&y+dy[i]<=n-1&&y+dy[i]>=0&&!v[x+dx[i]][y+dy[i]]){//走没走过的点  原因:防止死循环  
			dfs(x+dx[i],y+dy[i]);													//例子: 0 0 -> 0 1 -> 0 0 
		}
	}
}
bool c(int d){//用来判断当前难度差的范围内能不能满足条件
	for(int i=0;i+d<=120;i++){
		memset(v,0,sizeof v);
		flag=false;
		mmax=i+d;
		mmin=i;
		dfs(0,0);
		if(flag)return true;
	}
	return false;
}
void solve(){
	while(l<=r){
		mid=(l+r)/2;
		if(c(mid)){
			r=mid-1;
		}
		else l=mid+1;
	}
	cout << l;
	return ;
}
int main()
{
	scanf("%d",&n);
	memset(map,0,sizeof map);
	for(int i=0;i<n;i++){
		for(int j=0;j<n;j++){
			scanf("%d",*(map+i)+j);
		}
	}
	l=0;r=120;
	memset(v,0,sizeof v);
	solve();
	return 0;
}
posted @ 2019-04-24 22:11  correct  阅读(119)  评论(0)    收藏  举报