Проблема, которую я пытаюсь решить, следующая: я получаю N прямоугольные бумажные полоски шириной и длиной 1 см C. Мне нужно разрезать полоски на высоте, где сумма площадей разрезаемой полосы равна A. Вы можете увидеть пример нижнего ребра, для которого N = 5, полоски имеют длину, 5,3,6,2 и 3 см и A = 3 см, где разрез сделан на 4 см.Двоичный поиск дал несколько неточные результаты
Обратите внимание, что я ищу здесь для красной области.
Вход задается следующим образом. Первая строка в каждом случае начинается с двух целых чисел N (1 ≤ N ≤ 10^5) и (1 ≤ ≤ 10^9), представляющих соответственно количество полос и ожидаемый в результате площадь , Следующая строка содержит N целых чисел, представляющих длину C_i (1 < = C_i < = 10^4) каждой полосы. Вход заканчивается A = C = 0, который не должен обрабатываться.
Для каждого теста вывести в одной строке, высота Н разреза, что должно быть сделано так, чтобы сумма площади отрезанных полос равна cm². Распечатайте ответ с 4 знаками после запятой. Выход «: D», если резка не требуется, или «-.-», если это невозможно.
Эта проблема может быть найдена here
Моя идея для решения этой проблемы в том, чтобы использовать бинарный поиск, где я поднимаю высоту в середине полосы и сделать его больше или меньше в зависимости от того, был ли мой разрез слишком высокий или слишком низкий. Моя реализация задачи дается ниже:
#include <iostream>
#include <vector>
#include <iomanip>
#include <algorithm>
using namespace std;
int main(){
vector<int> v; // Vector that holds paper heights
int n; // Number of papers
double h, // Height of the cut
sum, // Area sum
min_n, // Minimum height for cut to happen
max_n, // Maximum height for cut to happen
a; // Desired final area
// Set desired output
cout << fixed << setprecision(4);
/* Get number of papers and desired area,
terminates if N = A = 0
*/
while(cin >> n >> a && (n||a)){
v.resize(n); // Resize vector to fit all papers
// Get all paper sizes
for(int i=0;i<n;i++){
cin >> v[i];
}
/* Sort the vector in decreasing order to
simplify the search
*/
sort(v.begin(),v.end(),greater<int>());
max_n = v[0]; // Largest possible cut is at the height of the largest paper
min_n = 0; // Smallest possible cut is at the base with height 0
// Iterate until answer is found
while(true){
// Initialize cut height as the average of smallest and largest cut sizes
h = (min_n + max_n)/2;
/* The area sum is equal to the sum of the areas of each cut, which is
given by the height of the paper minus the cut height. If the cut is
higher than the paper, the cut has area 0.
*/
sum = 0;
// Using mascoj sugenstion, a few changes were added
int s; // Temporary variable to hold number of time h is subtracted
for(int i=0; i<n;i++){
if(v[i] <= h) break; // From here onward cut area is 0 and there is no point adding
sum += v[i]; // Removed the subtraction inside of the for loop
s++; // Count how many paper strips were used
}
sum -= h*s // Subtracts the area cut from the s paper strips
// If the error is smaller than the significant value, cut height is printed
if(std::abs(sum-a) < 1e-5){
// If no cut is needed print :D else print cut height
(h < 1e-4 ? cout << ":D" << endl : cout << h << endl);
break;
}
// If max_n is "equal" to min_n and no answer was found, there is no answer
else if(max_n - min_n < 1e-7){
cout << "-.-" << endl;
break;
}
// Reduces search interval
sum < a ? max_n = h : min_n = h;
}
}
return 0;
}
Проблема заключается в том, после подачи моего ответа я получаю ошибку на 10%. На веб-сайте есть инструмент для сравнения вывода вашей программы с ожидаемым результатом, поэтому я запустил тестовый файл с более чем 1000 случайным образом сгенерированных тестовых примеров, и когда я сравнил оба, я получил ошибку округления в 4-м десятичном разряде, к сожалению, У меня есть файл или сценарий для создания тестовых примеров для меня. Я попытался изменить приемлемую ошибку на меньшую, но это не сработало. Кажется, я не могу найти ошибку, у любого из вас есть представление о том, что происходит?
пс: Несмотря на то, что проблема не говорит по описанию, вы можете получить порезы фракциях как высоты
Попробуйте заменить 'abs' на' std :: abs', чтобы вы случайно не вызывали 'int abs (int)' из 'cstdlib'. – Anton
Спасибо, но все же не так:/ –
_ «Напечатать ответ с помощью четырех знаков после запятой» означает «округление или усечение». Поэтому, прежде чем печатать значения, попробуйте вызвать ['std :: fesetround (FE_DOWNWARD);'] (http://en.cppreference.com/w/cpp/numeric/fenv/feround). – Anton