【发布时间】:2017-06-11 08:44:45
【问题描述】:
我要解决的问题如下:我得到 N 个 1 厘米宽和长 C 的矩形纸条。我需要在切割带的面积总和等于 A 的高度切割条带。您可以在下面看到一个示例,其中 N = 5,条带的长度分别为 5、3、6、2 和 3 厘米,A = 3 厘米,其中切口是4厘米。
请注意,我在这里寻找红色区域。
输入如下。每种情况的第一行都以两个整数 N (1 ≤ N ≤ 10^5) 和 A (1 ≤ A ≤ 10^9) 分别表示条带的数量和预期的结果面积。下一行包含 N 个整数,表示每个条带的长度 C_i (1 A = C = 0 结尾,不应处理。
对于每个测试用例,输出单行,切割的高度H,必须做到切割条的面积之和等于A强>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 位出现舍入错误,不幸的是,我没有没有文件也没有脚本来为我生成测试用例了。我尝试将可接受的错误更改为较小的错误,但这没有用。我似乎找不到错误,你们中有人知道发生了什么吗?
ps:虽然问题描述上没有说,但是你可以得到分数作为高度的削减
【问题讨论】:
-
尝试将
abs替换为std::abs,以确保您不会不小心从cstdlib调用int abs(int)。 -
谢谢芽,但仍然不是这样:/
-
“打印带 4 位小数的答案” 可以表示舍入或截断。所以也许在打印值之前尝试调用
std::fesetround(FE_DOWNWARD);。 -
一种风格建议:从 for 循环中删除
break并将条件移动到循环本身。for (i=0; i<n && v[i]>h; i++) -
您说您遇到了 10% 的错误,但您也说这是小数点后 4 位的错误,即 0.01%。是哪个?
标签: c++ c++11 search binary-search