二分查找(含题集)-C++实现

二分查找过程

首先,假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功;否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。

代码实现:

#include <stdio.h>
#define N 10
int main()
{
    int x; //x是要找的数
    int a[10];
    int lower, high; //左下标和右下标
    //输入
    scanf("%d", &x);
    for (int i = 0; i <= 9; i++)
    {
        scanf("%d", &a[i]);
    }

    lower = 0;    //右下标
    high = N - 1; //左下标
    int mid;      //记录中间下标
    while (lower <= high)
    {
        mid = (high - lower) / 2 + lower; //求中间下标:如果是用(high+low)/2
                                          //如果数太大的话,high+low可能会导致溢出
        if (x < a[mid])                   //说明x在当前范围的左边
        {
            high = mid - 1;
        }
        if (x > a[mid])                   //说明x在当前范围的右边
        {
            lower = mid + 1;
        }
        if (a[mid] == x)                  //如果找到 输出下标 直接退出就好了
        {
            printf("%d", mid);
            return 0;
        }
    }

    printf("no");

    return 0;
}

数列分段

在这里插入图片描述

方法一:

#include<iostream>
using namespace std;
int N, M, a[100000];
bool check(int mid) {
    int c = 1, s = 0;
    for (int i = 0; i < N; ++i) {
        if (mid < a[i]) {
            return false;
        }
        if (s+a[i] > mid) {
            ++c;
            s = a[i];
        } else {
            s += a[i];
        }
    }
    return c <= M;
}
int main(){
    cin >> N >> M;
    for (int i = 0; i < N; ++i) {
        cin >> a[i];
    }
    int L = 1, R = 1e9;
    while (L < R) {
        int mid = (L+R) / 2;
        if (check(mid)) R = mid;
        else L = mid + 1;
    }
    cout << L << endl;
    return 0;
}

方法二:

#include <iostream>
using namespace std;
int n, m, a[100005];
int F(int x);
int main()
{
    cin >> n >> m;
    int r = 0, l = 0;
    for (int i = 0; i < n; i++)
    {
        cin >> a[i];
        l = max(l, a[i]); //l取数列中最大的数,因为数列的和最小也得是 数列中最大的数
        r += a[i];        //和最大就是就分一个段,和就是总的数的和
                          //如果不这样r的范围就很难判断
    }
    int mid;
    int t = 0;
    while (l + 1 < r) //保留最后的r和l
    {
        mid = (r - l) / 2 + l;
        if (F(mid))
        {
            r = mid;
        }
        else
        {
            l = mid;
        }
    }
    if (F(l))
        cout << l;
    else
        cout << r;
    return 0;
}
int F(int x) //X就是每小段的和的最大值
{
    int t = 1; //当前开辟的段数  (最少也要1个段)
    int s = 0; //查看几个相邻的分为一个段 也就是控制一个段最大值为X  s为累加器
    for (int i = 0; i < n; i++)
    {
        if (s + a[i] <= x) //进行试探,看如果当前的段如果再加入一个数,会不会超出X
            s += a[i];     //如果不会超出,就直接把这个元素,放进来
        else
        {             //如果当前的段放不下,就再另开一个段,放后面的
            t++;      //开辟一个新段
            s = a[i]; //给新段第一个值 之后再用s进行累加
        }
    }
    if (t <= m)
        return 1; //当前X(和)的段数少于给定的m,也就是X太大了(因为X大了,每一段放的数就多,那么段数也就少了)
    else
        return 0;
}

列车调度

在这里插入图片描述

#include <iostream>
#include <set>
using namespace std;
int main(){
    int num, n;
	set<int> s;
    cin >> n;
    for(int i = 0; i < n; i++){
        cin >> num;
        if(s.upper_bound(num) != s.end())
            s.erase(s.upper_bound(num));
        s.insert(num);
    }
    cout << s.size();
    return 0;
}

待续…

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值