网线主管(信息学奥赛一本通- P1242)

二分答案求最大网线长度

【题目描述】

仙境的居民们决定举办一场程序设计区域赛。裁判委员会完全由自愿组成,他们承诺要组织一次史上最公正的比赛。他们决定将选手的电脑用星形拓扑结构连接在一起,即将它们全部连到一个单一的中心服务器。为了组织这个完全公正的比赛,裁判委员会主席提出要将所有选手的电脑等距离地围绕在服务器周围放置。

为购买网线,裁判委员会联系了当地的一个网络解决方案提供商,要求能够提供一定数量的等长网线。裁判委员会希望网线越长越好,这样选手们之间的距离可以尽可能远一些。

该公司的网线主管承接了这个任务。他知道库存中每条网线的长度(精确到厘米),并且只要告诉他所需的网线长度(精确到厘米),他都能够完成对网线的切割工作。但是,这次,所需的网线长度并不知道,这让网线主管不知所措。

你需要编写一个程序,帮助网线主管确定一个最长的网线长度,并且按此长度对库存中的网线进行切割,能够得到指定数量的网线。

【输入】

第一行包含两个整数N和K,以单个空格隔开。N(1 ≤ N ≤ 10000)是库存中的网线数,K(1 ≤ K ≤ 10000)是需要的网线数量。

接下来N行,每行一个数,为库存中每条网线的长度(单位:米)。所有网线的长度至少1m,至多100km。输入中的所有长度都精确到厘米,即保留到小数点后两位。

【输出】

网线主管能够从库存的网线中切出指定数量的网线的最长长度(单位:米)。必须精确到厘米,即保留到小数点后两位。

若无法得到长度至少为1cm的指定数量的网线,则必须输出“0.00”(不包含引号)。

【输入样例】

4 11
8.02
7.43
4.57
5.39

【输出样例】

2.00

这道题很好,要注意很多地方的细节,最重要的要意识到浮点数求二分要固定迭代次数,或者就是转化为整数再去做

//信息学奥赛一本通1242:网线主管 测试点都可以过的最终版本
#include <iostream>
#include <cmath>
using namespace std;
double a[10001];
int main(){
    int n,k;
    cin>>n>>k;
    for(int i=1;i<=n;i++) cin>>a[i];
    double l=0,r=100000;//切除的指定长度的网线长度进行二分
    for(int cnt=0;cnt<100;cnt++) {//使用固定迭代次数,避免浮点精度问题
        long long sum=0;
        double mid=(l+r)/2;
        if(mid < 1e-9) break;//避免除0
        for(int i=1;i<=n;i++)
            sum+=(long long)(a[i]/mid);
        if(sum<k) r=mid;
        else l=mid;
    }
    
    if(l<0.01) cout<<"0.00";
    else printf("%.2lf",floor(l * 100) / 100);//向下取整不然会四舍五入
    return 0;
}

/*
//信息学奥赛一本通1242:网线主管 很多测试点过不了
#include <iostream>
#include <cmath>
using namespace std;
double a[10001];
int main(){
    int n,k;
    cin>>n>>k;
    for(int i=1;i<=n;i++) cin>>a[i];
    double l=0,r=100000;//切除的指定长度的网线长度进行二分
    while(l+0.001<r) {//使用固定迭代次数,避免浮点精度问题
        long long sum=0;
        double mid=(l+r)/2;
        if(mid < 1e-9) break;//避免除0
        for(int i=1;i<=n;i++)
            sum+=(long long)(a[i]/mid);
        if(sum<k) r=mid;
        else l=mid;
    }
    
    if(l<0.01) cout<<"0.00";
    else printf("%.2lf",floor(l * 100) / 100);//向下取整不然会四舍五入
    return 0;
}
*/

/*
//信息学奥赛一本通1242:网线主管 有一个测试点过不了
#include <iostream>
#include <cmath>
using namespace std;
int a[10001];
int main(){
    int n,k;
    cin>>n>>k;
    for(int i=1;i<=n;i++){
        double x;
        cin>>x;
        a[i]=x*100;
    }
    int l=0,r=10000000;//切除的指定长度的网线长度进行二分
    while(l+1<r) {
        long long sum=0;
        int mid=(l+r)/2;
        for(int i=1;i<=n;i++)
            sum+=(a[i]/mid);
        if(sum<k) r=mid;
        else l=mid;
    }
    
    if(l<1) cout<<"0.00";
    else printf("%.2lf",l/100.0);//这里不能直接除100,应该除以100.0
    return 0;
}
*/

/*deepseek写法
//信息学奥赛一本通1242:网线主管 测试点全部都能过
#include <iostream>
#include <cmath>
using namespace std;

int main(){
    int n, k;
    cin >> n >> k;
    
    int a[10001];
    for(int i = 1; i <= n; i++){
        double x;
        cin >> x;
        a[i] = (int)(x * 100 + 0.5);
    }
    
    // 特殊情况处理
    if(k == 0){
        cout << "0.00";
        return 0;
    }
    
    if(k == 1){
        int max_len = 0;
        for(int i = 1; i <= n; i++){
            if(a[i] > max_len) max_len = a[i];
        }
        printf("%.2lf", max_len / 100.0);
        return 0;
    }
    
    int l = 1, r = 10000000;  // 从1开始,避免除0
    int ans = 0;
    
    while(l <= r){
        int mid = l + (r - l) / 2;
        
        long long sum = 0;
        for(int i = 1; i <= n; i++){
            sum += a[i] / mid;
        }
        
        if(sum >= k){
            ans = mid;
            l = mid + 1;
        } else {
            r = mid - 1;
        }
    }
    
    if(ans < 1){
        cout << "0.00";
    } else {
        printf("%.2lf", ans / 100.0);
    }
    return 0;
}
*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值