二分法求解相关问题

一.割绳子(Cable master)

输入格式: 输入文件的第一行包含两个整数 N 和 K,它们之间用空格隔开。N(1 = N = 10000)表示库存中的电缆数量,K(1 = K = 10000)表示请求的电缆数量。第一行后面是 N 行,每行一个数字,表示库存中每根电缆的长度(以米为单位)。所有电缆的长度至少为 1 米,最多为 100 千米。输入文件中的所有长度都以厘米为单位,小数点后精确到两位数。

输出格式: 将 Cable Master 可以从库存电缆中切割的部件的最大长度(以米为单位)写入输出文件,以获得所需的部件数量。该数字必须以厘米为精度写入,小数点后精确到两位数。 如果无法切割出所需数量的部件,每件至少一厘米长,则输出文件必须包含单个数字“0.00”(不带引号)。

输入样例: 4 11

8.02 7.43 4.57 5.39

输出样例: 2.00

代码:

#include <bits/stdc++.h>
using namespace std;  
  
int n, k;  
double len[100005];
  
bool check(double x) {  
    int num = 0;  
    for (int i=0;i<n;i++) {  
        num += (int)(len[i] / x);  
    }  
    return num >= k;  
}  
  
void solve(double left, double right) {  
    const double EPS = 1e-6;
    while (right - left > EPS) {  
        double mid = (left + right) / 2;  
        if (check(mid)) {  
            left = mid;  
        } else {  
            right = mid;  
        }  
    }  
    cout << fixed << setprecision(2) << (double)int((right * 100)) / 100 << endl;  
}  
  
int main() {  
    cin >> n >> k;  
    double right = 0;  
    for (int i = 0; i < n; i++) {  
        cin >> len[i];  
        right=right>len[i]?right:len[i];    //找出最长的绳子
    }  
    solve(0, right); 
    return 0;  
}

二. 二分法求函数的零点

有函数:f(x)=x 5 −15x 4 +85x 3 −225x 2 +274x−121 已知f(1.5)>0,f(2.4)<0 且方程f(x)=0 在区间[1.5,2.4] 有且只有一个根,请用二分法求出该根。

提示:判断函数是否为0,使用表达式 fabs(f(x)) < 1e-7

输入格式: 无。 输出格式:x

该方程在区间[1.5,2.4]中的根。要求四舍五入到小数点后6位。

 输入样例: 无

输出样例: 无

代码:

#include<bits/stdc++.h>
using namespace std;

double f(double x){
        return x*x*x*x*x-15*x*x*x*x+85*x*x*x-225*x*x+274*x-121;
}

void ling(double l,double r){
    if(f(l)*f(r)>=0) return;
    double x;
    x=(l+r)/2;
    while(fabs(f(x))>=1e-7){
        if(f(x)>0) l=x;
        else r=x;
        x=(l+r)/2;
    }
    cout<<fixed<<setprecision(6)<<x<<endl;
}

int main(){
double left=1.5;
    double right=2.4;
   ling(left,right);
}

三. maximum number in a unimodal array

You are a given a unimodal array of n distinct elements, meaning that its entries are in increasing order up until its maximum element, after which its elements are in decreasing order. Give an algorithm to compute the maximum element that runs in O(log n) time.

输入格式: An integer n in the first line, 1<= n <= 10000. N integers in the seconde line seperated by a space, which is a unimodal array.

输出格式: A integer which is the maximum integer in the array

输入样例: 7 1 2 3 9 8 6 5

输出样例: 9

代码:

#include<bits/stdc++.h>
using namespace std;
int n;
int a[10005];

void find(int left,int right){
    while (left < right) {  
        int mid = left + (right - left) / 2;
        if (a[mid] < a[mid + 1]) {  
            left = mid + 1;  
        } else {  
            right = mid;  
        }  
    }  
cout<<a[left];
}

int main(){
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>a[i];
    }
    int left=0;
    int right=n-1;
    find(left,right);
}

四.派

我的生日要到了!根据习俗,我需要将一些派分给大家。我有N个不同口味、不同大小的派。有F个朋友会来参加我的派对,每个人会拿到一块派(必须一个派的一块,不能由几个派的小块拼成;可以是一整个派)。 我的朋友们都特别小气,如果有人拿到更大的一块,就会开始抱怨。因此所有人拿到的派是同样大小的(但不需要是同样形状的),虽然这样有些派会被浪费,但总比搞砸整个派对好。当然,我也要给自己留一块,而这一块也要和其他人的同样大小。 请问我们每个人拿到的派最大是多少?每个派都是一个高为1,半径不等的圆柱体。

输入格式: 第一行包含两个正整数N和F,1 ≤ N, F ≤ 10 000,表示派的数量和朋友的数量。 第二行包含N个1到10000之间的整数,表示每个派的半径。

输出格式: 输出每个人能得到的最大的派的体积,精确到小数点后三位。

输入样例: 3 3 4 3 3

输出样例: 25.133

代码:

#include<bits/stdc++.h>
using namespace std;

double tiji(int radius) {  
    return M_PI * radius * radius * 1.0; 
}  
  
bool panduan(const vector<double>& volumes, double mid, int F) {  
    int sum = 0;  
    for (double volume : volumes) {  
        sum += static_cast<int>(volume / mid);  
    }  
    return sum >= F + 1;
}  
  
int main() {  
    int N, F;  
    cin >> N >> F;  
    vector<int> r(N);  
    vector<double> volumes(N);  

    double total = 0;  
    for (int i = 0; i < N; ++i) {  
        cin >> r[i];  
        double volume = tiji(r[i]);  
        volumes.push_back(volume);  
        total += volume;
    }  

    double left = 0, right = total/ (F + 1);
    double result = 0;  

    while (right - left > 1e-6) {  
        double mid = (left + right) / 2;  
        if (panduan(volumes, mid, F)) {  
            result = mid;  
            left = mid; 
        } else {  
            right = mid;
        }  
    }  
  
    cout << fixed << setprecision(3) << result << endl;  
    return 0;  
}

五.总结

二分法主要注意:

1.平分的两端范围,left和right (一般left取0,right取平均值或者给出数据中的最大值);

2.平分的中间端为(left+right)/2

3.while循环的终止条件为  right-left>1e-6,其中1e-6为0。

或者终止条件为right>=left

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值