#include <vector>
#include <iostream>
#include <algorithm>
using Matrix = std::vector<std::vector<int>>;
/**
* Class implementing std::reference_wrapper that
* cannot be rebound after creation.
**/
template <class T>
class single_bind_reference_wrapper {
// pointer to the original element
T *p_;
public:
// typedefs
using type = T;
// Construct/Copy/Destroy
single_bind_reference_wrapper(T& ref) noexcept : p_(std::addressof(ref)) {}
single_bind_reference_wrapper(T&&) = delete;
// Enable implicit convertsion from ref<T> to ref<const T>,
// or ref<Derived> to ref<Base>
template <class U, std::enable_if_t<std::is_convertible<U*, T*>{}, int> = 0>
single_bind_reference_wrapper(const single_bind_reference_wrapper<U>& other) noexcept :
p_(&other.get()) { }
// Assignment
template <class U>
decltype(auto) operator=(U &&u) const
noexcept(std::is_nothrow_assignable<T, U>{}) {
return get() = std::forward<U>(u);
}
decltype(auto) operator=(const single_bind_reference_wrapper& other) const
noexcept(std::is_nothrow_assignable<T, T>{}) {
return get() = other.get();
}
// Access
operator T& () const noexcept { return *p_; }
T& get() const noexcept { return *p_; }
};
template <class T>
void swap(single_bind_reference_wrapper<T> &lhs,
single_bind_reference_wrapper<T> &rhs)
noexcept(std::is_nothrow_move_constructible<T>::value &&
std::is_nothrow_move_assignable<T>::value){
auto tmp = std::move(lhs.get());
lhs = std::move(rhs.get());
rhs = std::move(tmp);
}
void rotate_mat (Matrix &mat, int r){
auto m = mat.size(); // Number of rows
auto n = mat[0].size(); // Number of columns
auto n_rings = std::min(m,n)/2; // Number of rings
for(auto ring_i=0; ring_i<n_rings; ++ring_i){
// The elements of the ring are stored sequentially
// in v_ring so it can be rotated with std::rotate
std::vector<single_bind_reference_wrapper<int>> v_ring;
// Top side of the ring
for(auto j=ring_i; j<=(n-1)-ring_i; ++j) {
v_ring.push_back(mat[ring_i][j]);
}
// Right side of the ring
for(auto i=ring_i+1; i<=(m-1)-ring_i; ++i) {
v_ring.push_back(mat[i][(n-1)-ring_i]);
}
// Bottom size of the ring
for(auto j=(n-1)-ring_i-1; j>ring_i; --j) {
v_ring.push_back(mat[(m-1)-ring_i][j]);
}
// Left size of the ring
for(auto i=(m-1)-ring_i; i>ring_i; --i) {
v_ring.push_back(mat[i][ring_i]);
}
std::rotate(v_ring.begin(),v_ring.begin()+r%v_ring.size(),v_ring.end());
}
};
Matrix read_matrix(int m, int n) {
Matrix mat;
mat.reserve(m);
for(auto i=0; i<m; ++i) {
mat.push_back(std::vector<int>{});
mat[i].reserve(n);
for(auto j=0; j<n; ++j) {
int x; std::cin >> x;
mat[i].push_back(x);
}
}
return mat;
};
void print_matrix(Matrix &mat){
for (auto& i : mat){
for (auto& j : i) {
std::cout << j << " ";
}
std::cout << "\n";
}
};
int main() {
int m,n; std::cin >> m >> n;
int r; std::cin >> r;
auto mat = read_matrix(m,n);
rotate_mat(mat,r);
print_matrix(mat);
return 0;
}
#include <vector>
#include <iostream>
#include <algorithm>
using Matrix = std::vector<std::vector<int>>;
/**
* Class implementing std::reference_wrapper that
* cannot be rebound after creation.
**/
template <class T>
class single_bind_reference_wrapper {
// pointer to the original element
T *p_;
public: // typedefs
using type = T;
// Construct/Copy/Destroy
single_bind_reference_wrapper(T& ref) noexcept : p_(std::addressof(ref)) {}
single_bind_reference_wrapper(T&&) = delete;
// Enable implicit convertsion from ref<T> to ref<const T>,
// or ref<Derived> to ref<Base>
template <class U, std::enable_if_t<std::is_convertible<U*, T*>{}, int> = 0>
single_bind_reference_wrapper(const single_bind_reference_wrapper<U>& other) noexcept :
p_(&other.get()) { }
// Assignment
template <class U>
decltype(auto) operator=(U &&u) const
noexcept(std::is_nothrow_assignable<T, U>{}) {
return get() = std::forward<U>(u);
}
decltype(auto) operator=(const single_bind_reference_wrapper& other) const
noexcept(std::is_nothrow_assignable<T, T>{}) {
return get() = other.get();
}
// Access
operator T& () const noexcept { return *p_; }
T& get() const noexcept { return *p_; }
};
template <class T>
void swap(single_bind_reference_wrapper<T> &lhs,
single_bind_reference_wrapper<T> &rhs)
noexcept(std::is_nothrow_move_constructible<T>::value &&
std::is_nothrow_move_assignable<T>::value){
auto tmp = std::move(lhs.get());
lhs = std::move(rhs.get());
rhs = std::move(tmp);
}
void rotate_mat (Matrix &mat, int r){
auto m = mat.size(); // Number of rows
auto n = mat[0].size(); // Number of columns
auto n_rings = std::min(m,n)/2; // Number of rings
for(auto ring_i=0; ring_i<n_rings; ++ring_i){
// The elements of the ring are stored sequentially
// in v_ring so it can be rotated with std::rotate
std::vector<single_bind_reference_wrapper<int>> v_ring;
// Top side of the ring
for(auto j=ring_i; j<=(n-1)-ring_i; ++j) {
v_ring.push_back(mat[ring_i][j]);
}
// Right side of the ring
for(auto i=ring_i+1; i<=(m-1)-ring_i; ++i) {
v_ring.push_back(mat[i][(n-1)-ring_i]);
}
// Bottom size of the ring
for(auto j=(n-1)-ring_i-1; j>ring_i; --j) {
v_ring.push_back(mat[(m-1)-ring_i][j]);
}
// Left size of the ring
for(auto i=(m-1)-ring_i; i>ring_i; --i) {
v_ring.push_back(mat[i][ring_i]);
}
std::rotate(v_ring.begin(),v_ring.begin()+r%v_ring.size(),v_ring.end());
}
};
Matrix read_matrix(int m, int n) {
Matrix mat;
mat.reserve(m);
for(auto i=0; i<m; ++i) {
mat.push_back(std::vector<int>{});
mat[i].reserve(n);
for(auto j=0; j<n; ++j) {
int x; std::cin >> x;
mat[i].push_back(x);
}
}
return mat;
};
void print_matrix(Matrix &mat){
for (auto& i : mat){
for (auto& j : i) {
std::cout << j << " ";
}
std::cout << "\n";
}
};
int main() {
int m,n; std::cin >> m >> n;
int r; std::cin >> r;
auto mat = read_matrix(m,n);
rotate_mat(mat,r);
print_matrix(mat);
return 0;
}
#include <vector>
#include <iostream>
#include <algorithm>
using Matrix = std::vector<std::vector<int>>;
/**
* Class implementing std::reference_wrapper that
* cannot be rebound after creation.
**/
template <class T>
class single_bind_reference_wrapper {
// pointer to the original element
T *p_;
public:
// typedefs
using type = T;
// Construct/Copy/Destroy
single_bind_reference_wrapper(T& ref) noexcept : p_(std::addressof(ref)) {}
single_bind_reference_wrapper(T&&) = delete;
// Enable implicit convertsion from ref<T> to ref<const T>,
// or ref<Derived> to ref<Base>
template <class U, std::enable_if_t<std::is_convertible<U*, T*>{}, int> = 0>
single_bind_reference_wrapper(const single_bind_reference_wrapper<U>& other) noexcept :
p_(&other.get()) { }
// Assignment
template <class U>
decltype(auto) operator=(U &&u) const
noexcept(std::is_nothrow_assignable<T, U>{}) {
return get() = std::forward<U>(u);
}
decltype(auto) operator=(const single_bind_reference_wrapper& other) const
noexcept(std::is_nothrow_assignable<T, T>{}) {
return get() = other.get();
}
// Access
operator T& () const noexcept { return *p_; }
T& get() const noexcept { return *p_; }
};
template <class T>
void swap(single_bind_reference_wrapper<T> &lhs,
single_bind_reference_wrapper<T> &rhs)
noexcept(std::is_nothrow_move_constructible<T>::value &&
std::is_nothrow_move_assignable<T>::value){
auto tmp = std::move(lhs.get());
lhs = std::move(rhs.get());
rhs = std::move(tmp);
}
void rotate_mat (Matrix &mat, int r){
auto m = mat.size(); // Number of rows
auto n = mat[0].size(); // Number of columns
auto n_rings = std::min(m,n)/2; // Number of rings
for(auto ring_i=0; ring_i<n_rings; ++ring_i){
// The elements of the ring are stored sequentially
// in v_ring so it can be rotated with std::rotate
std::vector<single_bind_reference_wrapper<int>> v_ring;
// Top side of the ring
for(auto j=ring_i; j<=(n-1)-ring_i; ++j) {
v_ring.push_back(mat[ring_i][j]);
}
// Right side of the ring
for(auto i=ring_i+1; i<=(m-1)-ring_i; ++i) {
v_ring.push_back(mat[i][(n-1)-ring_i]);
}
// Bottom size of the ring
for(auto j=(n-1)-ring_i-1; j>ring_i; --j) {
v_ring.push_back(mat[(m-1)-ring_i][j]);
}
// Left size of the ring
for(auto i=(m-1)-ring_i; i>ring_i; --i) {
v_ring.push_back(mat[i][ring_i]);
}
std::rotate(v_ring.begin(),v_ring.begin()+r%v_ring.size(),v_ring.end());
}
};
Matrix read_matrix(int m, int n) {
Matrix mat;
mat.reserve(m);
for(auto i=0; i<m; ++i) {
mat.push_back(std::vector<int>{});
mat[i].reserve(n);
for(auto j=0; j<n; ++j) {
int x; std::cin >> x;
mat[i].push_back(x);
}
}
return mat;
};
void print_matrix(Matrix &mat){
for (auto& i : mat){
for (auto& j : i) {
std::cout << j << " ";
}
std::cout << "\n";
}
};
int main() {
int m,n; std::cin >> m >> n;
int r; std::cin >> r;
auto mat = read_matrix(m,n);
rotate_mat(mat,r);
print_matrix(mat);
return 0;
}
I got the solution I was looking for from stackoverflow (check it here). Now it doesn't need the extra copy. I was expecting that this wouldn't be as verbose. I think being able to use the algorithms over a vector of references can be an useful feature.
#include <vector>
#include <iostream>
#include <algorithm>
using Matrix = std::vector<std::vector<int>>;
/**
* Class implementing std::reference_wrapper that
* cannot be rebound after creation.
**/
template <class T>
class single_bind_reference_wrapper {
// pointer to the original element
T *p_;
public: // typedefs
using type = T;
// Construct/Copy/Destroy
single_bind_reference_wrapper(T& ref) noexcept : p_(std::addressof(ref)) {}
single_bind_reference_wrapper(T&&) = delete;
// Enable implicit convertsion from ref<T> to ref<const T>,
// or ref<Derived> to ref<Base>
template <class U, std::enable_if_t<std::is_convertible<U*, T*>{}, int> = 0>
single_bind_reference_wrapper(const single_bind_reference_wrapper<U>& other) noexcept :
p_(&other.get()) { }
// Assignment
template <class U>
decltype(auto) operator=(U &&u) const
noexcept(std::is_nothrow_assignable<T, U>{}) {
return get() = std::forward<U>(u);
}
decltype(auto) operator=(const single_bind_reference_wrapper& other) const
noexcept(std::is_nothrow_assignable<T, T>{}) {
return get() = other.get();
}
// Access
operator T& () const noexcept { return *p_; }
T& get() const noexcept { return *p_; }
};
template <class T>
void swap(single_bind_reference_wrapper<T> &lhs,
single_bind_reference_wrapper<T> &rhs)
noexcept(std::is_nothrow_move_constructible<T>::value &&
std::is_nothrow_move_assignable<T>::value){
auto tmp = std::move(lhs.get());
lhs = std::move(rhs.get());
rhs = std::move(tmp);
}
void rotate_mat (Matrix &mat, int r){
auto m = mat.size(); // Number of rows
auto n = mat[0].size(); // Number of columns
auto n_rings = std::min(m,n)/2; // Number of rings
for(auto ring_i=0; ring_i<n_rings; ++ring_i){
// The elements of the ring are stored sequentially
// in v_ring so it can be rotated with std::rotate
std::vector<single_bind_reference_wrapper<int>> v_ring;
// Top side of the ring
for(auto j=ring_i; j<=(n-1)-ring_i; ++j) {
v_ring.push_back(mat[ring_i][j]);
}
// Right side of the ring
for(auto i=ring_i+1; i<=(m-1)-ring_i; ++i) {
v_ring.push_back(mat[i][(n-1)-ring_i]);
}
// Bottom size of the ring
for(auto j=(n-1)-ring_i-1; j>ring_i; --j) {
v_ring.push_back(mat[(m-1)-ring_i][j]);
}
// Left size of the ring
for(auto i=(m-1)-ring_i; i>ring_i; --i) {
v_ring.push_back(mat[i][ring_i]);
}
std::rotate(v_ring.begin(),v_ring.begin()+r%v_ring.size(),v_ring.end());
}
};
Matrix read_matrix(int m, int n) {
Matrix mat;
mat.reserve(m);
for(auto i=0; i<m; ++i) {
mat.push_back(std::vector<int>{});
mat[i].reserve(n);
for(auto j=0; j<n; ++j) {
int x; std::cin >> x;
mat[i].push_back(x);
}
}
return mat;
};
void print_matrix(Matrix &mat){
for (auto& i : mat){
for (auto& j : i) {
std::cout << j << " ";
}
std::cout << "\n";
}
};
int main() {
int m,n; std::cin >> m >> n;
int r; std::cin >> r;
auto mat = read_matrix(m,n);
rotate_mat(mat,r);
print_matrix(mat);
return 0;
}
lang-cpp