Suppose the following data structure:
std::map <int, std::vector<int> > M,
where val is represented by the sequence of vertices of the graph, and the key is the first vertex of the sequence. For example
{1} {1, 8, 12, 7}
{4} {4, 3, 5}
{7} {7, 9, 13, 18, 0, 2}
{2} {2, 11, 1}
{5} {5, 17, 10, 4}
{9} {9, 6, 19, 14}
{14} {14, 15, 9}
How to find all cycles (analogous start and end vertex) from the segments {}
C1: {1 8 12 7} {7 9 13 18 0 2} {2 11 1}
C2: {4 3 5} {5 17 10 4}
C3: {9 6 19 14} {14, 15, 9}
and how to avoid the duplicate sequence of segments, with the low time complexity (map may contain hundreds of thousands of sequences). Any cycle may contain n segments {}, where n>=1.
The initialization phase:
std::map <int, std::vector <int> > M;
M[1] = std::vector<int>{ 1, 8, 12, 7 };
M[4] = std::vector<int>{ 4, 3, 5 };
M[7] = std::vector<int>{ 7, 9, 13, 18, 0, 2 };
M[2] = std::vector<int>{ 2, 11, 1 };
M[5] = std::vector<int>{ 5, 17, 10, 4 };
M[9] = std::vector<int>{ 9, 6, 19, 14 };
M[14] = std::vector<int>{ 14, 15, 9 };
The draft of the algorithm:
std::vector<std::vector <int> > R;
for (auto im = M.begin(); im != M.end();)
{
std::vector<int> r, ri = im->second;
for(;;)
{
r.insert(r.end(), ri.begin(), ri.end());
ri = M[r.back()];
im = M.erase(M.find(im->first));
if (r.back() == r.front()) break;
}
R.push_back(r);
}
Unfortunately, the repeated deletion represents an expensive operation... I hope, there is a more beautiful and efficient solution :-)
Thanks for your help...
First, your inner loop needs to be a function (what if the paths don't cycle?)
Then, declare failure if either
The end node is numerically less than the start node (could be a cycle, but is not a canonical, so we won't print this shifted version)
The end node isn't found in the master table of paths
And that leads to a solution:
bool try_follow(int from, std::vector<int>& result)
{
int current = from;
while (true) {
auto path = M.find(current);
if (path == M.end()) return false;
current = path->second.back();
if (current < from) return false;
result.insert(result.end(), path->second.begin()+1, path->second.end());
if (current == from) return true;
}
}
int main(void)
{
for( auto& kvp : M )
{
std::vector<int> x;
if (try_follow(kvp.first, x)) {
std::cout << kvp.first;
for( int y : x )
std::cout << " - " << y;
std::cout << std::endl;
}
}
}
Demo: https://rextester.com/DWWZ9457
My first crack:
for (auto it : M)
{
if (it.first < it.second.back() && it.second.front() == M[it.second.back()].back())
std::cout << "Cycle between " << it.first << " and " << it.second.back() << '\n';
}
Won't find cycles that involve 3+ paths, of course.
Related
Imagine I have an ordered std::vector A = {x1, x2, ..., xn} and I want to perform an operation on every subsequent pair of items, e.g. f(x1, x2); f(x2, x3); ... f(xn-1, xn); f(xn, x1).
I could iterate like I normally would, while tracking the previous item:
for (auto x : A) {
...
f(previous_x, x);
previous_x = x;
}
f(previous_x, first_x);
But is there a better way to iterate through this vector? Are there features in the language that can streamline this?
Tried the solution provided. It works, but curious to know if there is a cleaner and more concise way.
Here you are
std::vector<int> v = { 1, 2, 3, 4, 5 };
for (std::vector<int>::size_type i = 0, n = std::size( v ); i < n; i++)
{
std::cout << v[i] + v[( i + 1 ) % n] << ' ';
}
std::cout << '\n';
the output of this code snippet is
3 5 7 9 6
You can use a similar approach.
Before the for loop you can check whether a vector contains at least two elements.
Ranges provide a beautiful solution for this case:
get the input vector,[1, 2, 3, 4, 5]
repeat it indefinitely with repeat,[[1, 2, 3, 4, 5], [1, 2, 3, 4, 5], ...]
flatten the new view out with join,[1, 2, 3, 4, 5, 1, 2, 3, 4, 5, ...]
take as many elements as the vector size plus one with take, and[1, 2, 3, 4, 5, 1]
apply a transformation to each adjacent pair with adjacent_transform<2>.[[1, 2], [2, 3], ...] -> [f(1,2), f(2,3), ...]
Notice repeat and adjacent_transform will be available in C++23.join and take should be available in C++20.
[Demo]
#include <fmt/ranges.h>
#include <functional> // multiplies, plus
#include <ranges>
#include <vector>
template <typename C, typename F>
auto my_adjacent_transform(C&& c, F&& f) {
return std::views::repeat(std::forward<C>(c))
| std::views::join
| std::views::take(c.size() + 1)
| std::views::adjacent_transform<2>(f);
}
int main() {
std::vector<int> v{ 1, 2, 3, 4, 5 };
fmt::print("v: {}\n", v);
fmt::print("Adding pairs: {}\n", my_adjacent_transform(v, std::plus<>{}));
fmt::print("Multiplying pairs: {}\n", my_adjacent_transform(
std::vector<int>{ 1, 2, 3, 4, 5 }, std::multiplies<>{}));
}
// Outputs:
//
// v: [1, 2, 3, 4, 5]
// Adding pairs: [3, 5, 7, 9, 6]
// Multiplying pairs: [2, 6, 12, 20, 5]
Alternatively, you could already use Eric Niebler's range-v3 library, and the solution would be quite similar:
get the input vector,[1, 2, 3, 4, 5]
repeat its contents indefinitely with cycle,[1, 2, 3, 4, 5, 1, 2, 3, 4, 5, ...]
take as many elements as the vector size plus one with take, [1, 2, 3, 4, 5, 1]
create a view of adjacent pairs with sliding(2), and[[1, 2], [2, 3], ...]
apply a transformation to each pair with transform.[t(1, 2), t(2, 3), ...]
Notice from the example below that range-v3 library lets you construct a container from a view via ranges::to. This conversion function will also be part of C++23.
[Demo]
#include <fmt/ranges.h>
#include <functional> // multiplies, plus
#include <range/v3/all.hpp>
#include <vector>
template <typename C, typename F>
auto my_adjacent_transform(C&& c, F&& f) {
auto t = [&f](auto&& p) { return std::forward<F>(f)(p[0], p[1]); };
return std::forward<C>(c)
| ranges::views::cycle
| ranges::views::take(c.size() + 1)
| ranges::views::sliding(2)
| ranges::views::transform(t);
}
int main() {
std::vector<int> v{ 1, 2, 3, 4, 5 };
fmt::print("v: {}\n", v);
fmt::print("Adding pairs: {}\n", my_adjacent_transform(v, std::plus<>{}));
auto w{ my_adjacent_transform(v, std::multiplies<>{})
| ranges::to<std::vector<int>>() };
fmt::print("Multiplying pairs: {}\n", w);
}
You could use an old-school non range based for-loop and dereference the current + next modulus A.size() iterator:
#include <iostream>
#include <vector>
void foo(int a, int b) { std::cout << a << ',' << b << '\n'; }
int main() {
std::vector<int> A{1, 2, 3};
if (A.size() >= 2) {
for (auto it = A.begin(); it != A.end(); ++it) {
foo(*it, *std::next(A.begin(),
(std::distance(A.begin(), it) + 1) % A.size()));
}
}
}
Output:
1,2
2,3
3,1
Or... use indices to do the same thing, like #Vlad showed.
Another option that would work with any type of container and iterators could be to save the first value that you get from dereferencing the initial iterator and reuse that when the loop ends.
Example:
#include <iostream>
#include <vector>
template <class It, class Func>
void do_pairwise(It first, It last, Func&& func) {
if (first == last) return;
auto curr = *first;
auto save = curr; // save the value for later
for (++first; first != last; curr = *first, ++first) {
func(curr, *first);
}
func(curr, save); // reuse the first value
}
int main() {
std::vector<int> A{1, 2, 3};
if (A.size() >= 2) {
do_pairwise(A.begin(), A.end(),
[](int a, int b) { std::cout << a << ',' << b << '\n'; });
}
}
Just do it:
A.push_back(A[0]); // copy first element to end
for (int j = 0; j < A.size() - 1; ++j)
f(A[j], A[j+1]);
I need to make a function which takes two parameters (two vectors of vectors) and as a result returns a vector of vectors which is a Kronecker product of two given vectors of vectors.
Whatever I do, my new vector of vectors is created by the same number (the one which should be only on the last position). For example if I have vector of vectors A: {3, -1},{0, 5} and B:{4,3,15},{0, -5, 2} my Kronecker product will be: {10, 10, 10, 10, 10, 10}, {10, 10, 10, 10, 10, 10} etc, instead of {12, 9, 45, -4, -3, -15}, {0, -15, 6, 0, 5, -2}, {0, 0, 0, 20, 15, 75}, {0, 0, 0, 0, -25, 10}
Matrix KroneckersProduct(Matrix A, Matrix B){
Matrix mat=CreateMatrix(NoRows(A)*NoRows(B),NoCols(A)*NoCols(B));
for(int i=0;i<NoRows(A)*NoRows(B);i++){
for(int j=0;j<NoCols(A)*NoCols(B);j++){
for(int k=0;k<NoRows(A);k++){
for(int l=0;l<NoRows(B);l++){
for(int m=0;m<NoCols(A);m++){
for(int n=0;n<NoCols(B);n++){
mat.at(i).at(j)=A.at(k).at(m)*B.at(l).at(n);
}
}
}
}
}
}
return mat;
}
This is the algorithm for Kronecker product. Maybe I switched v1 and v2
#include <vector>
#include <iostream>
using Matrix = std::vector<std::vector<double>>;
Matrix KroneckersProduct(Matrix v1, Matrix v2){
Matrix v(v1.size() * v2.size(), std::vector<double>(v1[0].size() * v2[0].size()));
for (std::size_t z1(0); z1 < v1.size(); ++z1) {
for (std::size_t z2(0); z2 < v2.size(); ++z2) {
for (std::size_t z3(0); z3 < v1[0].size(); ++z3) {
for (std::size_t z4(0); z4 < v2[0].size(); ++z4) {
v[z1*v2.size() + z2][z3*v2[0].size() + z4] = v1[z1][z3] * v2[z2][z4];
}
}
}
}
return v;
}
int main() {
Matrix v1{{3, -1},{0, 5}};
Matrix v2{{4,3,15}, {0, -5, 2}};
Matrix v(KroneckersProduct(v1, v2));
for (const auto& row : v) {
for (const auto& cell : row) {
std::cout << cell << " ";
}
std::cout << '\n';
}
return 0;
}
Output:
12 9 45 -4 -3 -15
0 -15 6 -0 5 -2
0 0 0 20 15 75
0 -0 0 0 -25 10
I have a 2d vector array which contains :
row id r b main
1 0 26 3
2 1 11 2
3 1 46 4
4 2 26 1
5 3 11 2
I want to sort every row based on its "main"-column value
smaller "main"-column.
smaller value => the entire row should be on the top.
if there is tow rows or more and there "main"-column have the same value, I want to check "r"-column.
smaller value => the entire row should be on the top.
after sorting it will look like this:
row id r b main
4 2 26 1
2 1 11 2
5 3 11 2
1 0 26 3
3 1 46 4
Try using std::sort like
using int_arr = std::array<int, 4>;
std::sort(std::begin(arr), std::end(arr), [](const int_arr& a, const int_arr& b){
return a[3] != b[3] ? a[3] < b[3] : a[1] < b[1];
});
Demo
#include <iostream>
#include <array>
#include <algorithm>
int main() {
using int_arr = std::array<int, 4>;
int_arr arr[5] = {
{1, 0, 26, 3},
{2, 1, 11, 2},
{3, 1, 46, 4},
{4, 2, 26, 1},
{5, 3, 11, 2}
};
for(const auto& i_arr : arr) {
for(const auto& i : i_arr)
std::cout<< i <<", ";
std::cout << "\n";
}
std::cout << "**************\n";
std::sort(std::begin(arr), std::end(arr), [](const int_arr& a, const int_arr& b){
return a[3] != b[3] ? a[3] < b[3] : a[1] < b[1];
});
for(const auto& i_arr : arr) {
for(const auto& i : i_arr)
std::cout<< i <<", ";
std::cout << "\n";
}
}
OutPut
1, 0, 26, 3,
2, 1, 11, 2,
3, 1, 46, 4,
4, 2, 26, 1,
5, 3, 11, 2,
**************
4, 2, 26, 1,
2, 1, 11, 2,
5, 3, 11, 2,
1, 0, 26, 3,
3, 1, 46, 4,
How is the y.size() = 4 in the following? The values in y are {11, 2, 4, 7} How does one arrive at this? What are a and b in the operator() function for each iteration of the set. I don't understand the construction of y and I can't find anything online that explains this situation. Thank You
#include <iostream>
#include <set>
struct C
{
bool operator()(const int &a, const int &b) const
{
return a % 10 < b % 10;
}
};
int main()
{
std::set<int> x({ 4, 2, 7, 11, 12, 14, 17, 2 });
std::cout << x.size() << std::endl;
std::set<int, C> y(x.begin(), x.end());
std::cout << y.size() << std::endl;
std::set<int>::iterator iter;
for (iter = y.begin(); iter != y.end(); ++iter)
{
std::cout << *iter << std::endl;
}
return 0;
}
Second template argument of set is comparator type — type of functor that implements less operation.
struct C
{
bool operator()(const int &a, const int &b) const
{
return a % 10 < b % 10;
}
};
This comparator will compare a and b as a < b only if a % 10 < b % 10, so practically all numbers will be compared by modulo 10.
UPDATE:
After pushing into x set numbers { 4, 2, 7, 11, 12, 14, 17, 2 }, set will contain seven elements { 2, 4, 7, 11, 12, 14, 17 }. These elements will be sorted in that way, because set stores objects in sorted way.
Then numbers from x set are being sequentially inserted into y set. Before inserting of each element, set will find proper place in sorted order of currently inserted numbers. If set will see, that there is already some number on it's place, set will not insert it.
After inserting {2, 4, 7} from x to y, y will be {2, 4, 7}.
Then, to insert 11 into y set will do comparisons of 11 with {2, 4, 7} to find proper place using provided C functor.
To check is 11 less than 2 set will call C()(11, 2), which will result in 11 % 10 < 2 % 10 comparison, which will result in true, so 11 will be inserted before 2.
Other numbers from x (12, 14, 17) will not be inserted, because set will find, that 12 should be on place of 2 (because 2 % 10 < 12 % 10 or 12 % 10 < 2 % 10 expression is false, so 2 == 12), and in same way 14 and 17.
I have an input file that I would like to use by using cin.
My input file contains a list of 9x9 numbers, such as:
1 2 3 4 5 6 7 8 9
2 2 3 4 5 6 7 8 9
3 2 3 4 5 6 7 8 9
4 2 3 4 5 6 7 8 9
5 ...
6 ...
7 ...
8 ...
9 ...
I want to store these values into a 2d array, so they would look like:
int board[9][9] = {{1, 2, 3, 4, 5, 6, 7, 8, 9},
{2, 2, 3, 4, 5, 6, 7, 8, 9},
{3, 2, 3, 4, 5, 6, 7, 8, 9},
{4, 2, 3, 4, 5, 6, 7, 8, 9},
{5, 2, 3, 4, 5, 6, 7, 8, 9},
{6, 2, 3, 4, 5, 6, 7, 8, 9},
{7, 2, 3, 4, 5, 6, 7, 8, 9},
{8, 2, 3, 4, 5, 6, 7, 8, 9},
{9, 2, 3, 4, 5, 6, 7, 8, 9}};
I tried to do:
int board[9][9];
for (int i=0;i<9;i++) {
for (int j=0;j<9;j++) {
std::cin >> board[i][j];
}
}
However, I don't think it's working. I'm going to use them as inputs when I run my code.
This works for me in GCC 4.9.0 with C++11:
Sample Code:
#include <iostream>
int main() {
int board[9][9];
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
std::cin >> board[i][j];
}
}
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
std::cout << board[i][j];
}
std::cout << std::endl;
}
return 0;
}
You should change C array for std::vector or other container from STL, it provide a lot of benefice (automatic memory management, array bound check, etc...). If you could use C++11, the new range for loop is a big improvement too (syntactical and performance wise, it avoid error as off by one, incorrect bounds, etc...).
Here is a C++11 version:
#include <iostream>
#include <vector>
int main() {
typedef std::vector<int> row_t;
typedef std::vector<row_t> board_t;
board_t board(9, row_t(9));
for (auto& row : board) {
for (auto& cell : row) {
std::cin >> cell;
}
}
for (const auto& row : board) {
for (auto cell : row) {
std::cout << cell;
}
std::cout << std::endl;
}
return 0;
}
The inner loop is wrong, there you have j++ as the loop condition. And as in the first iteration j will be zero (which in C++ is the same as false) the loop will not iterate at all. Besides, the inner loop is missing a semicolon, so it shouldn't even compile.