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

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;
}

发布了19 篇原创文章 · 获赞 0 · 访问量 508

猜你喜欢

转载自blog.csdn.net/qq_43317133/article/details/98486767