NOI题库(POJ)二分查找之——派 (全局题号:821)

题目来源:POJ

地址:http://noi.openjudge.cn/ch0111/05/

总时间限制: 
1000ms
内存限制: 
65536kB
描述

我的生日要到了!根据习俗,我需要将一些派分给大家。我有N个不同口味、不同大小的派。有F个朋友会来参加我的派对,每个人会拿到一块派(必须一个派的一块,不能由几个派的小块拼成;可以是一整个派)。

我的朋友们都特别小气,如果有人拿到更大的一块,就会开始抱怨。因此所有人拿到的派是同样大小的(但不需要是同样形状的),虽然这样有些派会被浪费,但总比搞砸整个派对好。当然,我也要给自己留一块,而这一块也要和其他人的同样大小。

请问我们每个人拿到的派最大是多少?每个派都是一个高为1,半径不等的圆柱体。

输入
  1. 第一行包含两个正整数N和F,1 ≤ N, F ≤ 10 000,表示派的数量和朋友的数量。
  2. 第二行包含N个1到10000之间的整数,表示每个派的半径。
输出输出每个人能得到的最大的派的体积,精确到小数点后三位。样例输入
3 3
4 3 3
样例输出
25.133

题目分析

  1. 利用二分查找寻求最大解。
  2. 利用函数确定所求最大姐是否满足条件
  3. 注意 pi的精准度

AC代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const double pi=3.141592653589;
const int maxn=10010;
int n,f,i;
int flag=0;
double sum=0;
double l,r,mid;
double a[maxn];
double v[maxn];

int result(double m,int f,int n,double v[])  {
	int num=0;
	for (int i=n-1; i>=0; i--)  {
		num+=(v[i]/m);
	}
	if (num<f) return 1;
	else  return 0;
}//result

void swap(double &x,double &y) {
	double temp;
	temp=x;
	x=y;
	y=temp;
	return;
}//swap

int main() {

	cin>>n>>f;
	f++;

	for(i=0; i<n; i++)
		cin>>a[i];

	for(i=0; i<n; i++) {
		v[i]=pi*a[i]*a[i];
		sum+=v[i];									 //总体积 正确
	}

	sort(v,v+n);                                     //快速排序

	l=0;
	r=v[n-1];
	mid = l-(l-r)/2;
	while (r-l>1e-5)  {
		if (result(mid,f,n,v))  {
			r=mid;
			mid=l-(l-r)/2;
		} else {
			l=mid;
			mid=l-(l-r)/2;
		}
	}

	printf("%.3f\n",l);

	return 0;
}

备注

AC码修改自同学代码,部分多余没有删除。

猜你喜欢

转载自blog.csdn.net/sang749992462/article/details/79554484