Related
I want to call parallel_reduce to sum the vector elements. But I find that if the vector elements is enough, the result is not correct. Please help me how to use this function.
// prepare data
const size_t allNum = 1000000;
std::vector<double> a;
for (int i = 0; i < allNum; ++i)
{
a.push_back(double(i + 1));
}
// λ func
auto f = [&]() -> double {
return tbb::parallel_reduce(tbb::blocked_range<size_t>(0, allNum),
0.0,
[&](const tbb::blocked_range<size_t>& r, double init) -> double {
for (int i = r.begin(); i < r.end(); ++i)
{
init += a[i];
}
return init;
},
[](double f, double s) -> double {
return f + s;
}
/*std::plus<double>()*/);
};
// call λ func, get the result
double correctResult = (1.0 + 1000000.0) * 500000.0;
double sum = f(); // sum != correctResult
// sum is different every loop
I tried running the above code. It was working fine and got the correct results too!
For more information about parallel_reduce, refer to the below links:
https://software.intel.com/content/www/us/en/develop/documentation/tbb-documentation/top/intel-threading-building-blocks-developer-reference/algorithms/parallelreduce-template-function.html
https://link.springer.com/content/pdf/10.1007%2F978-1-4842-4398-5.pdf
Thanks,
Santosh
Firstly, I would like to apologise for my bad English.
when I submit the code below to DomJudge I got TimeLimit ERROR.
I can't think of ways to solve this question albeit I searched all over the internet and still couldn't find a solution.
Can someone give me a hint?
Question:
Here are N linear function fi(x) = aix + bi, where 1 ≤ i ≤ N。Define F(x) = maxifi(x). Please compute
the following equation for the input c[i], where 1 ≤ i ≤ m.
**Σ(i=1 to m) F(c[i])**
For example, given 4 linear function as follows. f1(x) = –x, f2 = x, f3 = –2x – 3, f4 = 2x – 3. And the
input is c[1] = 4, c[2] = –5, c[3] = –1, c[4] = 0, c[5] = 2. We have F(c[1]) = 5, F(c[2]) = 7, F(c[3])
= 1, F(c[4]) = 0, F(c[5]) = 2. Then,
**Σ(i=1 to 5)𝐹(𝑐[𝑖])
= 𝐹(𝑐[1]) + 𝐹(𝑐[2]) + 𝐹(𝑐[3]) + 𝐹(𝑐[4]) + 𝐹([5]) = 5 + 7 + 1 + 0 + 2 = 15**
Input Format:
The first line contains two positive integers N and m. The next N lines will contain two integers ai
and bi, and the last line will contain m integers c[1], c[2], c[3],…, c[m]. Each element separated by
a space.
Output Format:
Please output the value of the above function.
question image:https://i.stack.imgur.com/6HeaA.png
Sample Input:
4 5
-1 0
1 0
-2 -3
2 -3
4 -5 -1 0 2
Sample Output:
15
My Program
#include <iostream>
#include <vector>
struct L
{
int a;
int b;
};
int main()
{
int n{ 0 };
int m{ 0 };
while (std::cin >> n >> m)
{
//input
std::vector<L> arrL(n);
for (int iii{ 0 }; iii < n; ++iii)
{
std::cin >> arrL[iii].a >> arrL[iii].b;
}
//find max in every linear polymore
int answer{ 0 };
for (int iii{ 0 }; iii < m; ++iii)
{
int input{ 0 };
int max{ 0 };
std::cin >> input;
max = arrL[0].a * input + arrL[0].b;
for (int jjj{ 1 }; jjj < n; ++jjj)
{
int tmp{arrL[jjj].a * input + arrL[jjj].b };
if (tmp > max)max = tmp;
}
answer += max;
}
//output
std::cout << answer << '\n';
}
return 0;
}
Your solution is O(n*m).
A faster solution is obtained by iteratively determinating the "dominating segments", and the correspong crossing points, called "anchors" in the following.
Each anchor is linked to two segments, on its left and on its right.
The first step consists in sorting the lines according to the a values, and then adding each new line iteratively.
When adding line i, we know that this line is dominant for large input values, and must be added (even if it will be removed in the following steps).
We calculate the intersection of this line with the previous added line:
if the intersection value is higher than the rightmost anchor, then we add a new anchor corresponding to this new line
if the intersection value is lower than the rightmost anchor, then we know that we have to suppress this last anchor value. In this case, we iterate the process, calculating now the intersection with the right segment of the previous anchor.
Complexity is dominated by sorting: O(nlogn + mlogm). The anchor determination process is O(n).
When we have the anchors, then determining the rigtht segment for each input x value is O(n+ m). If needed, this last value could be further reduced with a binary search (not implemented).
Compared to first version of the code, a few errors have been corrected. These errors were concerning some corner cases, with some identical lines at the extreme left (i.e. lowest values of a). Besides, random sequences have been generated (more than 10^7), for comparaison of the results with those obtained by OP's code. No differences were found. It is likely that if some errors remain, they correspond to other unknown corner cases. The algorithm by itself looks quite valid.
#include <iostream>
#include <vector>
#include <algorithm>
#include <cassert>
// lines of equation `y = ax + b`
struct line {
int a;
int b;
friend std::ostream& operator << (std::ostream& os, const line& coef) {
os << "(" << coef.a << ", " << coef.b << ")";
return os;
}
};
struct anchor {
double x;
int segment_left;
int segment_right;
friend std::ostream& operator << (std::ostream& os, const anchor& anc) {
os << "(" << anc.x << ", " << anc.segment_left << ", " << anc.segment_right << ")";
return os;
}
};
// intersection of two lines
double intersect (line& seg1, line& seg2) {
double x;
x = double (seg1.b - seg2.b) / (seg2.a - seg1.a);
return x;
}
long long int max_funct (std::vector<line>& lines, std::vector<int> absc) {
long long int sum = 0;
auto comp = [&] (line& x, line& y) {
if (x.a == y.a) return x.b < y.b;
return x.a < y.a;
};
std::sort (lines.begin(), lines.end(), comp);
std::sort (absc.begin(), absc.end());
// anchors and dominating segments determination
int n = lines.size();
std::vector<anchor> anchors (n+1);
int n_anchor = 1;
int l0 = 0;
while ((l0 < n-1) && (lines[l0].a == lines[l0+1].a)) l0++;
int l1 = l0 + 1;
if (l0 == n-1) {
anchors[0] = {0.0, l0, l0};
} else {
while ((l1 < n-1) && (lines[l1].a == lines[l1+1].a)) l1++;
double x = intersect(lines[l0], lines[l1]);
anchors[0] = {x, l0, l1};
for (int i = l1 + 1; i < n; ++i) {
if ((i != (n-1)) && lines[i].a == lines[i+1].a) continue;
double x = intersect(lines[anchors[n_anchor-1].segment_right], lines[i]);
if (x > anchors[n_anchor-1].x) {
anchors[n_anchor].x = x;
anchors[n_anchor].segment_left = anchors[n_anchor - 1].segment_right;
anchors[n_anchor].segment_right = i;
n_anchor++;
} else {
n_anchor--;
if (n_anchor == 0) {
x = intersect(lines[anchors[0].segment_left], lines[i]);
anchors[0] = {x, anchors[0].segment_left, i};
n_anchor = 1;
} else {
i--;
}
}
}
}
// sum calculation
int j = 0; // segment index (always increasing)
for (int x: absc) {
while (j < n_anchor && anchors[j].x < x) j++;
line seg;
if (j == 0) {
seg = lines[anchors[0].segment_left];
} else {
if (j == n_anchor) {
if (anchors[n_anchor-1].x < x) {
seg = lines[anchors[n_anchor-1].segment_right];
} else {
seg = lines[anchors[n_anchor-1].segment_left];
}
} else {
seg = lines[anchors[j-1].segment_right];
}
}
sum += seg.a * x + seg.b;
}
return sum;
}
int main() {
std::vector<line> lines = {{-1, 0}, {1, 0}, {-2, -3}, {2, -3}};
std::vector<int> x = {4, -5, -1, 0, 2};
long long int sum = max_funct (lines, x);
std::cout << "sum = " << sum << "\n";
lines = {{1,0}, {2, -12}, {3, 1}};
x = {-3, -1, 1, 5};
sum = max_funct (lines, x);
std::cout << "sum = " << sum << "\n";
}
One possible issue is the loss of information when calculating the double x corresponding to line intersections, and therefoe to anchors. Here is a version using Rational to avoid such loss.
#include <iostream>
#include <vector>
#include <algorithm>
#include <cassert>
struct Rational {
int p, q;
Rational () {p = 0; q = 1;}
Rational (int x, int y) {
p = x;
q = y;
if (q < 0) {
q -= q;
p -= p;
}
}
Rational (int x) {
p = x;
q = 1;
}
friend std::ostream& operator << (std::ostream& os, const Rational& x) {
os << x.p << "/" << x.q;
return os;
}
friend bool operator< (const Rational& x1, const Rational& x2) {return x1.p*x2.q < x1.q*x2.p;}
friend bool operator> (const Rational& x1, const Rational& x2) {return x2 < x1;}
friend bool operator<= (const Rational& x1, const Rational& x2) {return !(x1 > x2);}
friend bool operator>= (const Rational& x1, const Rational& x2) {return !(x1 < x2);}
friend bool operator== (const Rational& x1, const Rational& x2) {return x1.p*x2.q == x1.q*x2.p;}
friend bool operator!= (const Rational& x1, const Rational& x2) {return !(x1 == x2);}
};
// lines of equation `y = ax + b`
struct line {
int a;
int b;
friend std::ostream& operator << (std::ostream& os, const line& coef) {
os << "(" << coef.a << ", " << coef.b << ")";
return os;
}
};
struct anchor {
Rational x;
int segment_left;
int segment_right;
friend std::ostream& operator << (std::ostream& os, const anchor& anc) {
os << "(" << anc.x << ", " << anc.segment_left << ", " << anc.segment_right << ")";
return os;
}
};
// intersection of two lines
Rational intersect (line& seg1, line& seg2) {
assert (seg2.a != seg1.a);
Rational x = {seg1.b - seg2.b, seg2.a - seg1.a};
return x;
}
long long int max_funct (std::vector<line>& lines, std::vector<int> absc) {
long long int sum = 0;
auto comp = [&] (line& x, line& y) {
if (x.a == y.a) return x.b < y.b;
return x.a < y.a;
};
std::sort (lines.begin(), lines.end(), comp);
std::sort (absc.begin(), absc.end());
// anchors and dominating segments determination
int n = lines.size();
std::vector<anchor> anchors (n+1);
int n_anchor = 1;
int l0 = 0;
while ((l0 < n-1) && (lines[l0].a == lines[l0+1].a)) l0++;
int l1 = l0 + 1;
if (l0 == n-1) {
anchors[0] = {0.0, l0, l0};
} else {
while ((l1 < n-1) && (lines[l1].a == lines[l1+1].a)) l1++;
Rational x = intersect(lines[l0], lines[l1]);
anchors[0] = {x, l0, l1};
for (int i = l1 + 1; i < n; ++i) {
if ((i != (n-1)) && lines[i].a == lines[i+1].a) continue;
Rational x = intersect(lines[anchors[n_anchor-1].segment_right], lines[i]);
if (x > anchors[n_anchor-1].x) {
anchors[n_anchor].x = x;
anchors[n_anchor].segment_left = anchors[n_anchor - 1].segment_right;
anchors[n_anchor].segment_right = i;
n_anchor++;
} else {
n_anchor--;
if (n_anchor == 0) {
x = intersect(lines[anchors[0].segment_left], lines[i]);
anchors[0] = {x, anchors[0].segment_left, i};
n_anchor = 1;
} else {
i--;
}
}
}
}
// sum calculation
int j = 0; // segment index (always increasing)
for (int x: absc) {
while (j < n_anchor && anchors[j].x < x) j++;
line seg;
if (j == 0) {
seg = lines[anchors[0].segment_left];
} else {
if (j == n_anchor) {
if (anchors[n_anchor-1].x < x) {
seg = lines[anchors[n_anchor-1].segment_right];
} else {
seg = lines[anchors[n_anchor-1].segment_left];
}
} else {
seg = lines[anchors[j-1].segment_right];
}
}
sum += seg.a * x + seg.b;
}
return sum;
}
long long int max_funct_op (const std::vector<line> &arrL, const std::vector<int> &x) {
long long int answer = 0;
int n = arrL.size();
int m = x.size();
for (int i = 0; i < m; ++i) {
int input = x[i];
int vmax = arrL[0].a * input + arrL[0].b;
for (int jjj = 1; jjj < n; ++jjj) {
int tmp = arrL[jjj].a * input + arrL[jjj].b;
if (tmp > vmax) vmax = tmp;
}
answer += vmax;
}
return answer;
}
int main() {
long long int sum, sum_op;
std::vector<line> lines = {{-1, 0}, {1, 0}, {-2, -3}, {2, -3}};
std::vector<int> x = {4, -5, -1, 0, 2};
sum_op = max_funct_op (lines, x);
sum = max_funct (lines, x);
std::cout << "sum = " << sum << " sum_op = " << sum_op << "\n";
}
To reduce the time complexity from O(n*m) to something near O(nlogn), we need to order the input data in some way.
The m points where the target function is sampled can be easily sorted using std::sort, which has an O(mlogm) complexity in terms of comparisons.
Then, instead of searching the max between all the lines for each point, we can take advantage of a divide-and-conquer technique.
Some considerations can be made in order to create such an algorithm.
If there are no lines or no sample points, the answer is 0.
If there is only one line, we can evaluate it at each point, accumulating the values and return the result. In case of two lines we could easily accumulate the max between two values. Searching for the intersection and then separating the intervals to accumulate only the correct value may be more complicated, with multiple corner cases and overflow issues.
A recursive function accepting a list of lines, points and two special lines left and right, may start by calculating the middle point in the set of points. Then it could find the two lines (or the only one) that have the greater value at that point. One of them also have the greatest slope between all the ones passing for that maximum point, that would be the top "right". The other one, the top "left" (which may be the same one), have the least slope.
We can partition all the remaining lines in three sets.
All the lines having a greater slope than the "top right" one (but lower intercept). Those are the ones that we need to evaluate the sum for the subset of points at the right of the middle point.
All the lines having a lower slope than the "top left" one (but lower intercept). Those are the ones that we need to evaluate the sum for the subset of points at the left of the middle point.
The remaining lines, that won't partecipate anymore and can be removed. Note this includes both "top right" and "top left".
Having splitted both the points and the lines, we can recurively call the same function passing those subsets, along with the previous left line and "top left" as left and right to the left, and the "top right" line with the previous right as left and right to the right.
The return value of this function is the sum of the value at the middle point plus the return values of the two recursive calls.
To start the procedure, we don't need to evaluate the correct left and right at the extreme points, we can use an helper function as entry point which sorts the points and calls the recursive function passing all the lines, the points and two dummy values (the lowest possible line, y = 0 + std::numeric_limits<T>::min()).
The following is a possible implementation:
#include <algorithm>
#include <iostream>
#include <vector>
#include <numeric>
#include <limits>
struct Line
{
using value_type = long;
using result_type = long long;
value_type slope;
value_type intercept;
auto operator() (value_type x) const noexcept {
return static_cast<result_type>(x) * slope + intercept;
}
static constexpr Line min() noexcept {
return { 0, std::numeric_limits<value_type>::min()};
}
};
auto result_less_at(Line::value_type x)
{
return [x] (Line const& a, Line const& b) { return a(x) < b(x); };
}
auto slope_less_than(Line::value_type slope)
{
return [slope] (Line const& line) { return line.slope < slope; };
}
auto slope_greater_than(Line::value_type slope)
{
return [slope] (Line const& line) { return slope < line.slope; };
}
auto accumulate_results(Line const& line)
{
return [line] (Line::result_type acc, Line::value_type x) {
return acc + line(x);
};
}
struct find_max_lines_result_t
{
Line::result_type y_max;
Line left, right;
};
template< class LineIt, class XType >
auto find_max_lines( LineIt first_line, LineIt last_line
, Line left, Line right
, XType x )
{
auto result{ [left, right] (const auto max_left, const auto max_right)
-> find_max_lines_result_t {
if ( max_left < max_right )
return { max_right, right, right };
else if ( max_right < max_left )
return { max_left, left, left };
else
return { max_left, left, right };
}(left(x), right(x))
};
std::for_each( first_line, last_line
, [x, &result] (Line const& line) mutable {
auto const y{ line(x) };
if ( y == result.y_max ) {
if ( result.right.slope < line.slope )
result.right = line;
if ( line.slope < result.left.slope )
result.left = line;
}
else if ( result.y_max < y ) {
result = {y, line, line};
}
} );
return result;
}
template< class SampleIt >
auto sum_left_right_values( SampleIt const first_x, SampleIt const last_x
, Line const left, Line const right )
{
return std::accumulate( first_x, last_x, Line::result_type{},
[left, right] (Line::result_type acc, Line::value_type x) {
return acc + std::max(left(x), right(x)); } );
}
template< class LineIt, class XType >
auto find_max_result( LineIt const first_line, LineIt const last_line
, Line const left, Line const right
, XType const x )
{
auto const y_max{ std::max(left(x), right(x)) };
LineIt const max_line{ std::max_element(first_line, last_line, result_less_at(x)) };
return max_line == last_line ? y_max : std::max(y_max, (*max_line)(x));
}
template <class LineIt, class SampleIt>
auto sum_lines_max_impl( LineIt const first_line, LineIt const last_line,
SampleIt const first_x, SampleIt const last_x,
Line const left, Line const right )
{
if ( first_x == last_x ) {
return Line::result_type{};
}
if ( first_x + 1 == last_x ) {
return find_max_result(first_line, last_line, left, right, *first_x);
}
if ( first_line == last_line ) {
return sum_left_right_values(first_x, last_x, left, right);
}
auto const mid_x{ first_x + (last_x - first_x - 1) / 2 };
auto const top{ find_max_lines(first_line, last_line, left, right, *mid_x) };
auto const right_begin{ std::partition( first_line, last_line
, slope_less_than(top.left.slope) ) };
auto const right_end{ std::partition( right_begin, last_line
, slope_greater_than(top.right.slope) ) };
return top.y_max + sum_lines_max_impl( first_line, right_begin
, first_x, mid_x
, left, top.left )
+ sum_lines_max_impl( right_begin, right_end
, mid_x + 1, last_x
, top.right, right );
}
template <class LineIt, class SampleIt>
auto sum_lines_max( LineIt first_line, LineIt last_line
, SampleIt first_sample, SampleIt last_sample )
{
if ( first_line == last_line )
return Line::result_type{};
std::sort(first_sample, last_sample);
return sum_lines_max_impl( first_line, last_line
, first_sample, last_sample
, Line::min(), Line::min() );
}
int main()
{
std::vector<Line> lines{ {-1, 0}, {1, 0}, {-2, -3}, {2, -3} };
std::vector<long> points{ 4, -5, -1, 0, 2 };
std::cout << sum_lines_max( lines.begin(), lines.end()
, points.begin(), points.end() ) << '\n';
}
Testable here.
I have an input vector which can be of any size. What I want is to divide this vector into vectors of size 64 each and do something. The input vector's size should not necessarily be of size multiple to 64.
So let's say I have a vector of size 200, then I should divide it into 3 vectors of size 64 and 1 vector of size 8.
What I thought of so far is the following:
vector<double> inputVector;
vector<vector<double>> resultVector;
UInt16 length = inputVector.size();
int div = (length % 64) == 0 ? length / 64 : (length / 64) + 1;
for (int i = 0, j = 0; i < div; i++) {
vector<double> current
for (int k = 0; k < 64; k++) {
current.push_back(inputVector[j]);
if (j++ >= length) break;
}
resultVector.push_back(current);
if (j >= length) break;
}
I am sure there would be a better way of doing so but I could't find any example
You can use iterators to create a subvector:
vector<double> inputVector;
vector<vector<double>> resultVector;
for (auto it = inputVector.cbegin(), e = inputVector.cend(); it != inputVector.cend(); it = e) {
e = it + std::min<std::size_t>(inputVector.cend() - it, 64);
resultVector.emplace_back(it, e);
}
The simplest is just for each element push_back to some vector, keep track of them, and if the chunk size is reached then "flush" them to the output vector:
template<typename T>
std::vector<std::vector<T>> devide(const std::vector<T>& v, size_t chunk) {
// iterative algorithm
std::vector<T> tmp;
std::vector<std::vector<T>> ret;
size_t cnt = 0;
for (auto&& i : v) {
tmp.push_back(i);
++cnt;
if (cnt == chunk) {
cnt = 0;
ret.push_back(tmp);
tmp.clear();
}
}
if (cnt != 0) {
ret.push_back(tmp);
}
return ret;
}
but that iterative approach is not optimal - we could copy chunks of memory. So iterate over vector and copy up to chunk count of elements each loop - and copy less on the last loop.
template<typename T>
std::vector<std::vector<T>> devide2(const std::vector<T>& v, size_t chunk) {
// chunk algorithm
std::vector<std::vector<T>> ret;
const auto max = v.size();
for (size_t i = 0; i < max; ) {
const size_t chunkend = std::min(i + chunk, max);
ret.emplace_back(v.begin() + i, v.begin() + chunkend);
i = chunkend;
}
return ret;
}
Tested on godbolt.
More in STL style:
void even_slice(In b, In e, size_t n, F f)
{
while(std::distance(b, e) >= n) {
f(b, b + n);
b = b + n;
}
if (b != e) {
f(b, e);
}
}
template<typename In, typename Out>
Out even_slice_to_vetors(In b, In e, size_t n, Out out)
{
using ValueType = typename std::iterator_traits<In>::value_type;
using ItemResult = std::vector<ValueType>;
even_slice(b, e, n, [&out](auto x, auto y) { *out++ = ItemResult{x, y}; });
return out;
}
https://godbolt.org/z/zn9Ex1
Note that you know exactly how many subvectors have the wanted maximum size:
template<typename It>
auto subdivide_in_chunks(It first, It last, size_t chunk_size) {
using value_type = typename std::iterator_traits<It>::value_type;
size_t size{ std::distance(first, last) / chunk_size };
std::vector<std::vector<value_type>> ret;
ret.reserve(size);
auto last_chunk = std::next(first, size * chunk_size);
while ( first != last_chunk ) {
auto next = std::next(first, chunk_size);
ret.emplace_back(first, next);
first = next;
}
ret.emplace_back(first, last); // This is the last, shorter one.
return ret;
}
With range-v3, you could simply write:
namespace rs = ranges;
namespace rv = ranges::views;
auto resultVector = inputVector
| rv::chunk(64)
| rs::to<std::vector<std::vector<double>>>;
Here's a demo.
I have a vector of vector of vector
std::vector<std::vector<std::vector<double>>> mountain_table
and I would like to find the coordinates i, j, k of this vector for which it is the highest. I know that I should use max_element but I don't know how to use it in a 3d vector.
How should I get those coordinates?
I'd suggest to linearize your data in order to be able to use standard algorithms. The idea is to provide a couple of functions to get an index from 3D coords and vice et versa:
template<class T>
class Matrix3D // minimal
{
public:
using value_type = T;
using iterator = std::vector<value_type>::iterator;
private:
std::vector<value_type> _data;
size_t _sizex, _sizey, _sizez;
size_t index_from_coords(size_t x, size_t y, size_t z) const
{
return x*_sizex*_sizey + y*_sizey + z;
}
std::tuple<size_t, size_t, size_t> coords_from_index(size_t index) const
{
const size_t x = index / (_sizex * _sizey);
index = index % x;
const size_t y = index / _sizey;
const size_t z = index % _sizey;
return make_tuple(x, y, z);
}
public:
Matrix3D(size_t sizex, sizey, sizez) : _sizex(sizex), ... {}
T& operator()(size_t x, size_t y, size_t z) // add const version
{
return _data[index_from_coords(x, y, z)];
}
std::tuple<size_t, size_t, size_t> coords(iterator it)
{
size_t index = std::distance(begin(_data), it);
return coords_from_index(index);
}
iterator begin() { return begin(_data); }
iterator end() { return end(_data); }
}
Usage:
Matrix3D<double> m(3, 3, 3);
auto it = std::max_element(m.begin(), m.end()); // or min, or whatever from http://en.cppreference.com/w/cpp/header/algorithm
auto coords = m.coords(it);
std::cout << "x=" << coords.get<0>() << ... << "\n";
This is untested and incomplete code to give you a kickstart into better data design. i'd be happy to answer further questions about this idea in the comment below ;)
Here is how I would do it, by looping over the matrix, checking for highest values, and recording its indexes.
size_t highestI = 0;
size_t highestJ = 0;
size_t highestK = 0;
double highestValue = -std::numeric_limits<double>::infinity(); // Default value (Include <limits>)
for (size_t i = 0; i < mountain_table.size(); ++i)
{
for (size_t j = 0; j < mountain_table[i].size(); ++j)
{
for (size_t k = 0; k < mountain_table[i][j].size(); ++k)
{
if (mountain_table[i][j][k] > highestValue)
{
highestValue = mountain_table[i][j][k]; // Highest
// value needed to figure out highest indexes
// Stores the current highest indexes
highestI = i;
highestJ = j;
highestK = k;
}
}
}
}
This may not be the most efficient algorithm, but it gets the job done in an understandable way.
Since the max_element function is pretty short and easy to implement, I would suggest to write something similar yourself to fit your exact scenario.
// For types like this I would suggest using a type alias
using Vector3d = std::vector<std::vector<std::vector<double>>>;
std::array<size_t, 3> max_element(const Vector3d& vector) {
std::std::array<size_t, 3> indexes;
double biggest = vector[0][0][0];
for (unsigned i = 0; i < vector.size(); ++i)
for (unsigned j = 0; j < vector[i].size(); ++j)
for (unsigned k = 0; k < vector[i][j].size(); ++k)
if (value > biggest) {
biggest = value;
indexes = { i, j, k };
}
return indexes;
}
One other suggestion I could give you is to write your custom class Vector3d, with convenient functions like operator()(int x, int y, int z) etc. and save the data internally in simple vector<double> of size width * height * depth.
std::size_t rv[3] = {0};
std::size_t i = 0;
double max_value = mountain_table[0][0][0];
for (const auto& x : mountain_table) {
std::size_t j = 0;
for (const auto& y : x) {
auto it = std::max_element(y.begin(), y.end());
if (*it > max_value) {
rv[0] = i; rv[1] = j; rv[2] = it - y.begin();
max_value = *it;
}
++j;
}
++i;
}
I do not think you can use std::max_element for such data. You can use std::accumulate():
using dvect = std::vector<double>;
using ddvect = std::vector<dvect>;
using dddvect = std::vector<ddvect>;
dddvect mx = { { { 1, 2, 3 }, { -1, 3 }, { 8,-2, 3 } },
{ {}, { -1, 25, 3 }, { 7, 3, 3 } },
{ { -1, -2, -3 }, {}, { 33 } } };
struct max_value {
size_t i = 0;
size_t j = 0;
size_t k = 0;
double value = -std::numeric_limits<double>::infinity();
max_value() = default;
max_value( size_t i, size_t j, size_t k, double v ) : i( i ), j( j ), k( k ), value( v ) {}
max_value operator<<( const max_value &v ) const
{
return value > v.value ? *this : v;
}
};
auto max = std::accumulate( mx.begin(), mx.end(), max_value{}, [&mx]( const max_value &val, const ddvect &ddv ) {
auto i = std::distance( &*mx.cbegin(), &ddv );
return std::accumulate( ddv.begin(), ddv.end(), val, [i,&ddv]( const max_value &val, const dvect &dv ) {
auto j = std::distance( &*ddv.cbegin(), &dv );
return std::accumulate( dv.begin(), dv.end(), val, [i,j,&dv]( const max_value &val, const double &d ) {
auto k = std::distance( &*dv.cbegin(), &d );
return val << max_value( i, j, k, d );
} );
} );
} );
live example. Code could be simplified if C++14 or later allowed but I am not sure that it would worse the effort and data reorganization most probably would work better (you would be able to use std::max_element() on singe vector for example). On another side this layout supports jagged matrix as shown on example (different size subarrays)
You should use "for" loop , because you don't have 3d vector.
for (size_t i = 0; i <mountain_table.size(); ++i)
{
for (size_t j = 0; j < mountain_table[i].size() ++j)
{
// find max element index k here and check if it is maximum.
// If yes save i, j, k and update max val
}
}
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How do you detect where two line segments intersect?
Determining if two line segments intersect?
Given are two lines l1=((A0, B0), (A1, B1)) and l2=((A2, B2), (A3, B3)); Ax, Bx are integers and (Ax, Bx) specify the starts and ends of the lines.
Is there a algorithm using only integer arithmetic that determines if l1 and l2 intersect? (Only a Boolean answer is needed.)
My own approach was to compute a point near the intersection point with fixed-point arithmetic. The solution (a, b) was then substituted in the following equations:
I: abs((A0 + a * (A1-A0)) - (A2 + b * (A3-A2))) < tolerance
II: abs((B0 + a * (B1-B0)) - (B2 + b * (B3-B2))) < tolerance
My method should return true if both I and II evaluate to true.
My C++-Code:
vec.h:
#ifndef __MY_VECTOR__
#define __MY_VECTOR__
#include <stdarg.h>
template<typename VType, unsigned int dim>
class vec {
private:
VType data[dim];
public:
vec(){}
vec(VType v0, ...){
data[0] = v0;
va_list l;
va_start(l, v0);
for(unsigned int i=1; i<dim; ++i){
data[i] = va_arg(l, VType);
}
va_end(l);
}
~vec(){}
VType& operator[](unsigned int i){
return data[i];
}
VType operator[](unsigned int i) const {
return data[i];
}};
template<typename VType, unsigned int dim, bool doDiv>
vec<VType, dim> helpArith1(const vec<VType, dim>& A, long delta){
vec<VType, dim> r(A);
for(unsigned int i=0; i<dim; ++i){
r[i] = doDiv ? (r[i] / delta) : (r[i] * delta);
}
return r;
}
template<typename VType, unsigned int dim>
vec<VType, dim> operator*(const vec<VType, dim>& v, long delta) {
return helpArith1<VType, dim, false>(A, delta);
}
template<typename VType, unsigned int dim>
vec<VType, dim> operator*(long delta, const vec<VType, dim>& v){
return v * delta;
}
template<typename VType,unsigned int dim>
vec<VType, dim> operator/(const vec<VType, dim>& A, long delta) {
return helpArith1<VType, dim, true>(A, delta);
}
template<typename VType, unsigned int dim, bool doSub>
vec<VType, dim> helpArith2(const vec<VType, dim>& A, const vec<VType, dim>& B){
vec<VType, dim> r;
for(unsigned int i=0; i<dim; ++i){
r[i] = doSub ? (A[i]-B[i]):(A[i]+B[i]);
}
return r;
}
template<typename VType, unsigned int dim>
vec<VType, dim> operator+(const vec<VType, dim>& A, const vec<VType, dim>& B){
return helpArith2<VType, dim, false>(A, B);
}
template<typename VType, unsigned int dim>
vec<VType, dim> operator-(const vec<VType, dim>& A, const vec<VType, dim>& B){
return helpArith2<VType, dim, true>(A, B);
}
template<typename VType, unsigned int dim>
bool operator==(const vec<VType, dim>& A, const vec<VType, dim>& B) {
for(unsigned int i==0; i<dim; ++i){
if(A[i]!=B[i]){
return false;
}
}
return true;
}
template<typename VType, unsigned int dim>
bool operator!=(const vec<VType, dim>& A, const vec<VType, dim>& B) {
return !(A==B);
}
#endif
line.h:
#ifndef __MY_LINE__
#define __MY_LINE__
#include "vec.h"
unsigned long int ggt(unsigned long int A, unsigned long int B) {
if(A==0) {
if(B==0) {
return 1;
}
return B;
}
while(B!=0) {
unsigned long int temp = A % B;
A = B;
B = temp;
}
return A;
}
#define ABS(n) ( ((n)<0) ? (-n) : (n) )
struct line {
vec<long int, 2> A, B;
explicit line(long int iA_0, long int iA_1, long int iB_0, long int iB_1) :
A(vec<long int, 2>(iA_0<<8, iA_1<<8)),
B(vec<long int, 2>(iB_0<<8, iB_1<<8)){}
vec<long int, 2> slope() const{
vec<long int, 2> temp = A-B;
if(temp[0]<0) {
temp[0] = -1 * temp[0];
temp[1] = -1 * temp[1];
}
return temp/ggt(ABS(temp[0]), ABS(temp[1]));
}
};
bool intersect(line l1, line l2) {
const long int epsilon = 1<<4;
vec<long int, 2> sl1 = l1.slope(), sl2 = l2.slope();
// l2.A + b*sl2 = l1.A + a*sl1
// <=> l2.A - l1.A = a*sl1 - b*sl2 // = (I, II)^T
// I': sl2[1] * I; II': sl2[0] * II
vec<long int, 2> L = l2.A - l1.A, R = sl1;
L[0] = L[0] * sl2[1]; R[0] = R[0] * sl2[1];
L[1] = L[1] * sl2[0]; R[1] = R[1] * sl2[0];
// I' - II'
long int L_SUB = L[0] - L[1], R_SUB = R[0] - R[1];
if(ABS(R_SUB) == 0) {
return ABS(L_SUB) == 0;
}
long int temp = ggt(ABS(L_SUB), ABS(R_SUB));
L_SUB /= temp; R_SUB /= temp;
// R_SUB * a = L_SUB
long int a = L_SUB/R_SUB, b = ((l1.A[0] - l2.A[0])*R_SUB + L_SUB * sl1[0])/R_SUB;
// if the given lines intersect, then {a, b} must be the solution of
// l2.A - l1.A = a*sl1 - b*sl2
L = l2.A - l1.A;
long x = ABS((L[0]- (a*sl1[0]-b*sl2[0]))), y = ABS((L[1]- (a*sl1[1]-b*sl2[1])));
return x<epsilon && y < epsilon;
}
#endif
main.cpp:
#include "line.h"
int main(){
line A(0, 0, 6, 0), B(3, 3, 4, -3);
bool temp = intersect(A, B);
return 0;
}
(I am not sure if my intersect function works for all lines, but with the test data I used so far it returned with the correct result.)
This is possible. We want to check whether both endpoins of l1 are on different sides of l2, and both endpoints of l2 are on opposite sides of l1.
To check on which side of l1=((A0, B0), (A1, B1)) a point (A, B) lies, we take:
an arbitrary normal vector N perpendicular to the line; one such vector is (B1-B0, A1-A0)
the vector P from the start of the line to the point (A, B), which is (A-A0, B-B0)
We then compute the dot product:
N · P = (A-A0, B-B0) · (B1-B0, A1-A0) = (A-A0) * (B1-B0) + (B-B0) * (A1-A0)
We're only interested in the sign: if it's positive, the point is on one side of the line; if it's negative, it's on the other. As you see, no floating point arithmetic required.
We can take advantage of the fact that numbers with opposite signs, when multiplied, always yield negative. So the full expression to determine whether two line segments ((A0, B0), (A1, B1)) and ((A2, B2), (A3, B3)) intersect is:
((A2-A0)*(B1-B0) - (B2-B0)*(A1-A0)) * ((A3-A0)*(B1-B0) - (B3-B0)*(A1-A0)) < 0
&&
((A0-A2)*(B3-B2) - (B0-B2)*(A3-A2)) * ((A1-A2)*(B3-B2) - (B1-B2)*(A3-A2)) < 0
Test Code
Some C++ code to test the above calculation:
#include <iostream>
#include <cstdlib>
struct Point {
int x,y;
};
bool isIntersecting(Point& p1, Point& p2, Point& q1, Point& q2) {
return (((q1.x-p1.x)*(p2.y-p1.y) - (q1.y-p1.y)*(p2.x-p1.x))
* ((q2.x-p1.x)*(p2.y-p1.y) - (q2.y-p1.y)*(p2.x-p1.x)) < 0)
&&
(((p1.x-q1.x)*(q2.y-q1.y) - (p1.y-q1.y)*(q2.x-q1.x))
* ((p2.x-q1.x)*(q2.y-q1.y) - (p2.y-q1.y)*(q2.x-q1.x)) < 0);
}
int main(int argc, char* argv[]) {
if(argc != 9) {
std::cout << "Call as " << argv[0] << " <p1.x> <p1.y> <p2.x> "
<< "<p2.y> <q1.x> <q1.y> <q2.x> <q2.y>" << std::endl;
return -1;
}
Point p1 = {.x = atoi(argv[1]), .y = atoi(argv[2])};
Point p2 = {.x = atoi(argv[3]), .y = atoi(argv[4])};
Point q1 = {.x = atoi(argv[5]), .y = atoi(argv[6])};
Point q2 = {.x = atoi(argv[7]), .y = atoi(argv[8])};
if(isIntersecting(p1,p2,q1,q2)) {
std::cout << "Segments intersect" << std::endl;
return 1;
}
else {
std::cout << "Segments do not intersect" << std::endl;
return 0;
}
}
Results:
$ ./intersection_test 0 0 10 10 0 10 10 0 # example from the comments
Segments intersect
$ ./intersection_test 0 1 2 1 1 2 1 0
Segments intersect
$ ./intersection_test 0 0 0 1 1 1 1 0
Segments do not intersect
$ ./intersection_test 1 1 5 3 3 4 7 2 # q touches but not intersects at p2
Segments do not intersect
$ ./intersection_test 1 1 5 3 3 4 6 2
Segments intersect
Two line segments intersect iff their lines intersect and the endpoints of each line segment are on opposite sides of the other segments line. At least in 2d.
Two lines intersect is an easy question in 2d.
Which side of a line a point is on is also easy.
Neither require non integer math.
I would estimate a dozen or three lines for some general geometry code, then a 6 to 10 line solution? Plus language boilerplate. And some zero length corner case checks.
Note I am distinguishing lines from segments.