二分查找應用分析(Cable master 2019年北大叉院機試原題--坑點精度問題)

查找一般應用:

  1. 查找,是從輸入數據找到特定要求的數據
  2. 經常和排序結合,快速查找
  3. 在排序的基礎上,二分查找是常見的題型

對於整型:

l=1,r=n;
while(l<r){
	int mid = l+(r+1-l)/2;
	if(a[mid]<q) l=mid;
	else r = mid-1;
}

對於浮點型:

double eps = 1e-5;//精度
	while(eps<r-l){
	double mid=(l+r)/2;
	if(check(mid))  l=mid;
	else  r= mid;
}

例題解析:

Cable master 2019年北大叉院機試原題 D - Cable master

試題內容:

Inhabitants of the Wonderland have decided to hold a regional programming contest. The Judging Committee has volunteered and has promised to organize the most honest contest ever. It was decided to connect computers for the contestants using a “star” topology - i.e. connect them all to a single central hub. To organize a truly honest contest, the Head of the Judging Committee has decreed to place all contestants evenly around the hub on an equal distance from it.
To buy network cables, the Judging Committee has contacted a local network solutions provider with a request to sell for them a specified number of cables with equal lengths. The Judging Committee wants the cables to be as long as possible to sit contestants as far from each other as possible.
The Cable Master of the company was assigned to the task. He knows the length of each cable in the stock up to a centimeter,and he can cut them with a centimeter precision being told the length of the pieces he must cut. However, this time, the length is not known and the Cable Master is completely puzzled.
You are to help the Cable Master, by writing a program that will determine the maximal possible length of a cable piece that can be cut from the cables in the stock, to get the specified number of pieces.

input

The first line of the input file contains two integer numb ers N and K, separated by a space. N (1 = N = 10000) is the number of cables in the stock, and K (1 = K = 10000) is the number of requested pieces. The first line is followed by N lines with one number per line, that specify the length of each cable in the stock in meters. All cables are at least 1 meter and at most 100 kilometers in length. All lengths in the input file are written with a centimeter precision, with exactly two digits after a decimal point.

output

Write to the output file the maximal length (in meters) of the pieces that Cable Master may cut from the cables in the stock to get the requested number of pieces. The number must be written with a centimeter precision, with exactly two digits after a decimal point.
If it is not possible to cut the requested number of pieces each one being at least one centimeter long, then the output file must contain the single number “0.00” (without quotes).

Sample Input

4 11
8.02
7.43
4.57
5.39

Sample Output

2.00

題意分析:

有n條不同長度的網線,需要從中裁剪出K段,求K段網線的最大長度。
網線主管能夠從庫存的網線中切出指定數量的網線的最長長度(單位:米)。必須精確到釐米,即保留到小數點後兩位。若無法得到長度至少爲1cm的制定數量的網線,則必須輸出“0.00”(不包含引號)。

解題分析:
題目考點:精度問題

對於精度問題需要知道的點:
//都是表示PI,但是結果卻是不一樣的, 不同的原因在於浮點計算會丟失精度

double a = asin( sqrt( 2.0 ) / 2 ) * 4.0;
double b = acos( -1.0 );
  output:a = 3.14159265358979360000;b = 3.14159265358979310000;
  		 a - b = 0.00000000000000044409

現在考慮一種情況,題目要求輸出保留兩位小數。有個case的正確答案的精確值是0.005,按理應該輸出0.01,但你的結果可能是0.005000000001(恭喜),也有可能是0.004999999999(悲劇),如果按照printf(“%.2lf”, a)輸出,那你的遭遇將和括號裏的字相同。

第一種解決辦法是,如果a爲正,則輸出a+eps, 否則輸出a-eps
第二種方法:100次精度超級高,基本問題不大,算好複雜度無腦上就完事了
第三種就是用while(r-l>eps);

for(int i = 0; i < 100; ++i) {
        double mid = (l + r) / 2;
        if(check(mid)) l = mid;
        else r = mid;
    }
    return l;

題目坑點:保留兩位小數,並不是四捨五入;

輸出需要 printf("%.2lf",(int)(r*100)/100.0);

具體代碼如下:

#include <cstdio>
#include <cmath>
#include <string>
using namespace std;
const int mMax = 10010;
int n,k;
double a[mMax];
double eps = 1e-3; //題目中說要保留後兩位,因此精度至少要後推一位
bool check(double mid, int k){
	int num = 0;
	for(int i=0;i<n;i++){
		num += (int)(a[i]/mid);
	}
	if(num>=k) return true;
	else return false;
}
int main(){
	scanf("%d%d",&n,&k);
	double l=0,r=-1,mid=0; //r是數組a中最大的元素
	for(int i=0;i<n;i++){
			scanf("%lf",&a[i]);
			if(a[i]>r) r=a[i];
		}
	while(r-l>eps){
			mid =(r+l)/2.0;
			if(check(mid,k)) l= mid;
			else r=mid;
		}
	printf("%.2lf\n",(int)(r*100)/100.0);
	return 0;
}

勉勵:
一切纔剛剛開始,加油!ヾ(◍°∇°◍)ノ゙

如果覺得我的文章對你有所幫助與啓發,點贊給我個鼓勵吧(づ ̄3 ̄)づ╭❤~
關注我和我一起共勉加油吧!
如果文章有錯誤,還望不吝指教!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章