POJ北大 1064 (fjutacm 2290)割绳子 二分法

本文探讨了一道经典的绳子切割问题,即如何从n条绳子中切割出K条相同长度的绳子,使得这些绳子的长度尽可能长。文章通过实例解释了问题的输入和输出格式,并提出了一种有效的解决策略——二分法。通过设定合理的边界和迭代次数,实现了对最优解的精确逼近,避免了暴力解法的效率低下。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Problem Description

已知有n条绳子,每根绳子至少1米,每条绳子都有一定的长度(单位,米),从中切割出K条长度相同的绳子,求这K条绳子每条最长能有多长?绳子的长度不能小于1厘米,如果不能满足输出 0.00,答案向下保留两位小数(比如1.799999向下保留两位后是1.79 即后面的数字全部舍去)。


1,这里提醒一下,C题要求的是向下保留两位小数,所以不能直接使用%.2f(%.2f是四舍五入到小数点后两位)

Input

输入一行有两个数N,K(1<=N,K<=10000).

第二行有N个数,表示每条绳子的长度(1<=Li<=100000),每个输入都有两位小数.

输入double用%lf,输出用%f,用scanf输入.

Output

输出满足条件的绳子的最长长度(向下保留两位小数).

SampleInput

4 11
8.02
7.43
4.57
5.39

SampleOutput

2.00

这题难点是能不能联想到用二分法去求解。虽然N只有1e4,但是牵扯到小数,如果暴力的话,极有可能是1e41e51e2,血T。所以用二分去遍历所有可能的解,省时间省脑力,二分板子一套,让电脑自己跑去,只不过要根据题意稍作修改。注释才是重点 ,不多BB上代码。

#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <stack>
#include <queue>
#include <vector>
#include <math.h>
#include <iostream>
#include <string.h>
const int MAX=1e4+5;
using namespace std;
typedef long long ll;
double len[MAX];

double td(int n, double k)
{
  double l=0, r=200000, m; /// 左右界尽量往两边拓,不要太多也不要刚刚好,怕极
                           ///限数据,两边的值没被遍历到
  int cnt, i, j;
  for (j=0; j<250; j++)/// 因为是小数,不要用while(l<r),直接给它指定多次循环,
  {                    ///来保证答案的准确性,至于到底来几次,参考2^n >= 1e11
    m = (l+r)/2;
    cnt = 0;        /// 每一次判断都记得要把cnt初始化
    for (i=0; i<n; i++)
      cnt += (int)(len[i]/m);/// cnt记下临时解m带来的结果,和k去进行比较
/// 这里没有cnt==k的return,和上面j的循环同理,毕竟要求最大解,cnt是向下取整
///的,很可能还没取到最大解,就直接满足条件return了
    if (cnt<k)/// 小于说明绳子割长了,把右边界往左缩
      r = m;
    else      /// 大于(等于放哪都一样)说明绳子割短了,再割长点试试
      l = m;
  }
  return r;   /// 要最大解,把最终的右边界返回。至于正常的二分查找的返回值,
}             ///我再研究研究,搞懂了再去二分法板子那里更新

int main()
{
  int N, K, i, j;
  cin >> N >> K;
  for (i=0; i<N; i++)
    scanf ("%lf", &len[i]);
  double ans=td(N, K)*100;/// 题目说了不四舍五入,所以我用了土办法,取几位我
  ans = (int)ans;         ///乘几位,然后向下取整,最后再除回去
  ans /= 100;
  printf("%.2f", ans);    ///这时候不用担心会四舍五入了,小数点后两位后都是0
  return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值