I was solving problems on HackerRank when I got stuck at this one.
Problem Statement
You are given a 2D matrix, a, of dimension MxN and a positive integer R. You have to rotate the matrix R times and print the resultant matrix. Rotation should be in anti-clockwise direction.
Rotation of a 4x5 matrix is represented by the following figure. Note that in one rotation, you have to shift elements by one step only (refer sample tests for more clarity).
It is guaranteed that the minimum of M and N will be even.
Input
First line contains three space separated integers, M, N and R, where M is the number of rows, N is number of columns in matrix, and R is the number of times the matrix has to be rotated.
Then M lines follow, where each line contains N space separated positive integers. These M lines represent the matrix.
Output
Print the rotated matrix.
Constraints
2 <= M, N <= 300
1 <= R <= 10^9
min(M, N) % 2 == 0
1 <= aij <= 108, where i ∈ [1..M] & j ∈ [1..N]'
What I tried to do was store the circles in a 1D array. Something like this.
while(true)
{
k = 0;
for(int j = left; j <= right; ++j) {temp[k] = a[top][j]; ++k;}
top++;
if(top > down || left > right) break;
for(int i = top; i <= down; ++i) {temp[k] = a[i][right]; ++k;}
right--;
if(top > down || left > right) break;
for(int j = right; j >= left; --j) {temp[k] = a[down][j] ; ++k;}
down--;
if(top > down || left > right) break;
for(int i = down; i >= top; --i) {temp[k] = a[i][left]; ++k;}
left++;
if(top > down || left > right) break;
}
Then I could easily rotate the 1D matrix by calculating its length modulo R. But then how do I put it back in matrix form? Using a loop again would possibly cause a timeout.
Please don't provide code, but only give suggestions. I want to do it myself.
Solution Created :
#include <iostream>
using namespace std;
int main() {
int m,n,r;
cin>>m>>n>>r;
int a[300][300];
for(int i = 0 ; i < m ; ++i){
for(int j = 0; j < n ; ++j)
cin>>a[i][j];
}
int left = 0;
int right = n-1;
int top = 0;
int down = m-1;
int tleft = 0;
int tright = n-1;
int ttop = 0;
int tdown = m-1;
int b[300][300];
int k,size;
int temp[1200];
while(true){
k=0;
for(int i = left; i <= right ; ++i)
{
temp[k] = a[top][i];
// cout<<temp[k]<<" ";
++k;
}
++top;
if(top > down || left > right)
break;
for(int i = top; i <= down ; ++i)
{
temp[k]=a[i][right];
// cout<<temp[k]<<" ";
++k;
}
--right;
if(top > down || left > right)
break;
for(int i = right; i >= left ; --i)
{
temp[k] = a[down][i];
// cout<<temp[k]<<" ";
++k;
}
--down;
if(top > down || left > right)
break;
for(int i = down; i >= top ; --i)
{
temp[k] = a[i][left];
// cout<<temp[k]<<" ";
++k;
}
++left;
if(top > down || left > right)
break;
//________________________________\\
size = k;
k=0;
// cout<<size<<endl;
for(int i = tleft; i <= tright ; ++i)
{
b[ttop][i] = temp[(k + (r%size))%size];
// cout<<(k + (r%size))%size<<" ";
// int index = (k + (r%size))%size;
// cout<<index;
++k;
}
++ttop;
for(int i = ttop; i <= tdown ; ++i)
{
b[i][tright]=temp[(k + (r%size))%size];
++k;
}
--tright;
for(int i = tright; i >= tleft ; --i)
{
b[tdown][i] = temp[(k + (r%size))%size];
++k;
}
--tdown;
for(int i = tdown; i >= ttop ; --i)
{
b[i][tleft] = temp[(k + (r%size))%size];
++k;
}
++tleft;
}
size=k;
k=0;
if(top != ttop){
for(int i = tleft; i <= tright ; ++i)
{
b[ttop][i] = temp[(k + (r%size))%size];
++k;
}
++ttop;
}
if(right!=tright){
for(int i = ttop; i <= tdown ; ++i)
{
b[i][tright]=temp[(k + (r%size))%size];
++k;
}
--tright;
}
if(down!=tdown){
for(int i = tright; i >= tleft ; --i)
{
b[tdown][i] = temp[(k + (r%size))%size];
++k;
}
--tdown;
}
if(left!=tleft){
for(int i = tdown; i >= ttop ; --i)
{
b[i][tleft] = temp[(k + (r%size))%size];
++k;
}
++tleft;
}
for(int i = 0 ; i < m ;++i){
for(int j = 0 ; j < n ;++j)
cout<<b[i][j]<<" ";
cout<<endl;
}
return 0;
}
You need to break down this problem (remind me of an interview question from gg and fb) :
Solve first rotating a sequence one a single position
Then solve rotating a sequence N times
Model each "circle" or ring as an array. You may or may not actually need to store in a separate data
Iterate over each ring and apply the rotating algorithm
Lets consider the case of an array of length L which needs to be rotated R time. Observe that if R is a multiple of L, the array will be unchanged.
Observe too that rotating x times to the right is the same as rotating L - x to the left (and vice versa).
Thus you can first design an algorithm able to rotate once either left or right one exactly one position
Reduce the problem of rotating R times to the left to rotating R modulo L to the left
If you want to go further reduce the problem of rotating R modulo L to the left to rotating left R modulo L or rotating right L - R modulo L. Which means if you have 100 elements and you have to do 99 rotations left, you better do 1 rotation right and be done with it.
So the complexity will be O ( Number of circles x Circle Length x Single Rotation Cost)
With an array in-place it means O( min(N,m) * (N * M)^2 )
If you use a doubly linked list as temporary storage, a single rotation sequence is done by removing the front and putting it at the tail (or vice versa to rotate right). So what you can do is copy all data first to a linked list. Run the single rotation algorithm R modulo L times, copy back the linked list on the ring position, and move on the next right till all rings are processed.
Copy ring data to list is O(L), L <= N*M
Single Rotation Cost is O(1)
All rotations R modulo L is O(L)
Repeat on all min(N,m) rings
With a spare double linked list it means complexity of O( min(N,m) * (N * M))
I would start with a simplifying assumption: M is less than or equal to N. Thus, you are guaranteed to have an even number of rows. (What if M > N? Then transpose the matrix, carry out the algorithm, and transpose the matrix again.)
Because you have an even number of rows, you can easily find the corners of each cycle within the matrix. The outermost cycle has these corners:
a1,1 → aM,1 → aM,N → a1,N
To find the next cycle, move each corner inward, which means incrementing or decrementing the index at each corner as appropriate.
Knowing the sequence of corners allows you to iterate over each cycle and store the values in a one-dimensional vector. In each such vector a, start from index R % a.size() and increment the index a.size() - 1 times to iterate over the rotated elements of the cycle. Copy each element a[i % a.size()] back to the cycle.
Note that we don't actually rotate the vector. We accomplish the rotation by starting from an offset index when we copy elements back to the matrix. Thus, the overall running time of the algorithm is O(MN), which is optimal because it costs O(MN) just to read the input matrix.
I would treat this as a problem that divides the matrix into submatrices. You could probably write a function that shifts the matrices (and submatrices) outer rows and columns by one each time you call it. Take care to handle the four corners of the matrix appropriately.
Check this out for suggestions how to shift the columns.
Edit (more detailed):
Read each matrix circle in as a vector, use std::rotate on it R % length.vector times, write back. Maximally 150 operations.
Each element moves uniquely according to one of four formulas, adding five movements of known sizes (I'll leave the size calculation out since you wanted to figure it out):
formula (one of these four):
left + down + right + up + left
down + right + up + left + down
right + up + left + down + right
up + left + down + right + up
Since the smallest side of the matrix is even, we know there is not an element remaining in place. After R rotations, the element has circled around floor (R / formula) times but still needs to undergo extra = R % formula shifts. Once you know extra, simply calculate the appropriate placement for the element.
Related
Here's the problem I have a hard time solving.
You are given a ciphertext Y and a sequence of cyclic shifts that had produced Y from string Z, the shift with parameters (i, j, k) applies to the substring Z[i..j] (from i-th to j-th character, inclusive) and cyclicly rotates it to the right k times. String characters are numbered starting from one. Given the above information, your task is to guess the initial cleartext X.
Input:
The first line contains the ciphertext, which is a nonempty string consisting of N lowercase English letters (1 ≤ N ≤ 50000). The second line contains the number of shifts M (1 ≤ M ≤ 50000).
The following M lines describe the sequence of cyclic shifts (in the order of their application to the cleartext). Each shift is described by three parameters i, j, k (1 ≤ i < j ≤ N, 1 ≤ k ≤ j − i).
Example of input:
logoduck
3
1 3 1
4 5 1
1 4 1
As output you should provide the deciphered text (``goodluck'' for example).
The obvious approach is to try and reverse each shift starting from the last one. It seems that this approach is not time-efficient. However, I can't come up with any ideas how to do it any other way, so any help is appreciated.
I attach my code:
#include <iostream>
#include <vector>
#include <string>
int main() {
std::string message;
std::cin >> message;
int number_of_elements = message.size();
int elements[number_of_elements];
for (int i = 0; i < number_of_elements; ++i) {
elements[i] = i;
}
int number_of_shifts;
std::cin >> number_of_shifts;
std::vector<std::vector<int>> shifts(number_of_shifts);
for (int iterator = 0; iterator < number_of_shifts; ++iterator) {
int left, right, by;
std::cin >> left >> right >> by;
--left;
--right;
shifts[iterator].push_back(left);
shifts[iterator].push_back(right);
shifts[iterator].push_back(by);
}
for (int iterator = number_of_shifts - 1; -1 < iterator; --iterator) {
int current[number_of_elements];
int left, right, by;
left = shifts[iterator][0];
right = shifts[iterator][1];
by = shifts[iterator][2];
for (int j = right; left - 1 < j; --j) {
if (j - by < left) {
current[right + 1 - (left - (j - by))] = elements[j];
} else {
current[j - by] = elements[j];
}
}
for (int j = left; j < right + 1; ++j) {
elements[j] = current[j];
}
}
for (int i = 0; i < number_of_elements; ++i) {
std::cout << message.substr(elements[i], 1);
}
return 0;
}
You can do this in O(M log N) time using a data structure called a "rope", which is like a string that supports splitting and concatenation in O(log N) time: https://en.wikipedia.org/wiki/Rope_(data_structure)
Rotations can be build from these operations, of course.
The implementation is a binary tree, B-tree, or similar with limited-size strings in the leaves.
It's not hard to find C++ implementations, but unfortunately, the STL doesn't have one. If you have to implement it yourself, it's a little tricky.
Hexagonal grid is represented by a two-dimensional array with R rows and C columns. First row always comes "before" second in hexagonal grid construction (see image below). Let k be the number of turns. Each turn, an element of the grid is 1 if and only if the number of neighbours of that element that were 1 the turn before is an odd number. Write C++ code that outputs the grid after k turns.
Limitations:
1 <= R <= 10, 1 <= C <= 10, 1 <= k <= 2^(63) - 1
An example with input (in the first row are R, C and k, then comes the starting grid):
4 4 3
0 0 0 0
0 0 0 0
0 0 1 0
0 0 0 0
Simulation: image, yellow elements represent '1' and blank represent '0'.
This problem is easy to solve if I simulate and produce a grid each turn, but with big enough k it becomes too slow. What is the faster solution?
EDIT: code (n and m are used instead R and C) :
#include <cstdio>
#include <cstring>
using namespace std;
int old[11][11];
int _new[11][11];
int n, m;
long long int k;
int main() {
scanf ("%d %d %lld", &n, &m, &k);
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) scanf ("%d", &old[i][j]);
}
printf ("\n");
while (k) {
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
int count = 0;
if (i % 2 == 0) {
if (i) {
if (j) count += old[i-1][j-1];
count += old[i-1][j];
}
if (j) count += (old[i][j-1]);
if (j < m-1) count += (old[i][j+1]);
if (i < n-1) {
if (j) count += old[i+1][j-1];
count += old[i+1][j];
}
}
else {
if (i) {
if (j < m-1) count += old[i-1][j+1];
count += old[i-1][j];
}
if (j) count += old[i][j-1];
if (j < m-1) count += old[i][j+1];
if (i < n-1) {
if (j < m-1) count += old[i+1][j+1];
count += old[i+1][j];
}
}
if (count % 2) _new[i][j] = 1;
else _new[i][j] = 0;
}
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) old[i][j] = _new[i][j];
}
k--;
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
printf ("%d", old[i][j]);
}
printf ("\n");
}
return 0;
}
For a given R and C, you have N=R*C cells.
If you represent those cells as a vector of elements in GF(2), i.e, 0s and 1s where arithmetic is performed mod 2 (addition is XOR and multiplication is AND), then the transformation from one turn to the next can be represented by an N*N matrix M, so that:
turn[i+1] = M*turn[i]
You can exponentiate the matrix to determine how the cells transform over k turns:
turn[i+k] = (M^k)*turn[i]
Even if k is very large, like 2^63-1, you can calculate M^k quickly using exponentiation by squaring: https://en.wikipedia.org/wiki/Exponentiation_by_squaring This only takes O(log(k)) matrix multiplications.
Then you can multiply your initial state by the matrix to get the output state.
From the limits on R, C, k, and time given in your question, it's clear that this is the solution you're supposed to come up with.
There are several ways to speed up your algorithm.
You do the neighbour-calculation with the out-of bounds checking in every turn. Do some preprocessing and calculate the neighbours of each cell once at the beginning. (Aziuth has already proposed that.)
Then you don't need to count the neighbours of all cells. Each cell is on if an odd number of neighbouring cells were on in the last turn and it is off otherwise.
You can think of this differently: Start with a clean board. For each active cell of the previous move, toggle the state of all surrounding cells. When an even number of neighbours cause a toggle, the cell is on, otherwise the toggles cancel each other out. Look at the first step of your example. It's like playing Lights Out, really.
This method is faster than counting the neighbours if the board has only few active cells and its worst case is a board whose cells are all on, in which case it is as good as neighbour-counting, because you have to touch each neighbours for each cell.
The next logical step is to represent the board as a sequence of bits, because bits already have a natural way of toggling, the exclusive or or xor oerator, ^. If you keep the list of neigbours for each cell as a bit mask m, you can then toggle the board b via b ^= m.
These are the improvements that can be made to the algorithm. The big improvement is to notice that the patterns will eventually repeat. (The toggling bears resemblance with Conway's Game of Life, where there are also repeating patterns.) Also, the given maximum number of possible iterations, 2⁶³ is suspiciously large.
The playing board is small. The example in your question will repeat at least after 2¹⁶ turns, because the 4×4 board can have at most 2¹⁶ layouts. In practice, turn 127 reaches the ring pattern of the first move after the original and it loops with a period of 126 from then.
The bigger boards may have up to 2¹⁰⁰ layouts, so they may not repeat within 2⁶³ turns. A 10×10 board with a single active cell near the middle has ar period of 2,162,622. This may indeed be a topic for a maths study, as Aziuth suggests, but we'll tacke it with profane means: Keep a hash map of all previous states and the turns where they occurred, then check whether the pattern has occurred before in each turn.
We now have:
a simple algorithm for toggling the cells' state and
a compact bitwise representation of the board, which allows us to create a hash map of the previous states.
Here's my attempt:
#include <iostream>
#include <map>
/*
* Bit representation of a playing board, at most 10 x 10
*/
struct Grid {
unsigned char data[16];
Grid() : data() {
}
void add(size_t i, size_t j) {
size_t k = 10 * i + j;
data[k / 8] |= 1u << (k % 8);
}
void flip(const Grid &mask) {
size_t n = 13;
while (n--) data[n] ^= mask.data[n];
}
bool ison(size_t i, size_t j) const {
size_t k = 10 * i + j;
return ((data[k / 8] & (1u << (k % 8))) != 0);
}
bool operator<(const Grid &other) const {
size_t n = 13;
while (n--) {
if (data[n] > other.data[n]) return true;
if (data[n] < other.data[n]) return false;
}
return false;
}
void dump(size_t n, size_t m) const {
for (size_t i = 0; i < n; i++) {
for (size_t j = 0; j < m; j++) {
std::cout << (ison(i, j) ? 1 : 0);
}
std::cout << '\n';
}
std::cout << '\n';
}
};
int main()
{
size_t n, m, k;
std::cin >> n >> m >> k;
Grid grid;
Grid mask[10][10];
for (size_t i = 0; i < n; i++) {
for (size_t j = 0; j < m; j++) {
int x;
std::cin >> x;
if (x) grid.add(i, j);
}
}
for (size_t i = 0; i < n; i++) {
for (size_t j = 0; j < m; j++) {
Grid &mm = mask[i][j];
if (i % 2 == 0) {
if (i) {
if (j) mm.add(i - 1, j - 1);
mm.add(i - 1, j);
}
if (j) mm.add(i, j - 1);
if (j < m - 1) mm.add(i, j + 1);
if (i < n - 1) {
if (j) mm.add(i + 1, j - 1);
mm.add(i + 1, j);
}
} else {
if (i) {
if (j < m - 1) mm.add(i - 1, j + 1);
mm.add(i - 1, j);
}
if (j) mm.add(i, j - 1);
if (j < m - 1) mm.add(i, j + 1);
if (i < n - 1) {
if (j < m - 1) mm.add(i + 1, j + 1);
mm.add(i + 1, j);
}
}
}
}
std::map<Grid, size_t> prev;
std::map<size_t, Grid> pattern;
for (size_t turn = 0; turn < k; turn++) {
Grid next;
std::map<Grid, size_t>::const_iterator it = prev.find(grid);
if (1 && it != prev.end()) {
size_t start = it->second;
size_t period = turn - start;
size_t index = (k - turn) % period;
grid = pattern[start + index];
break;
}
prev[grid] = turn;
pattern[turn] = grid;
for (size_t i = 0; i < n; i++) {
for (size_t j = 0; j < m; j++) {
if (grid.ison(i, j)) next.flip(mask[i][j]);
}
}
grid = next;
}
for (size_t i = 0; i < n; i++) {
for (size_t j = 0; j < m; j++) {
std::cout << (grid.ison(i, j) ? 1 : 0);
}
std::cout << '\n';
}
return 0;
}
There is probably room for improvement. Especially, I'm not so sure how it fares for big boards. (The code above uses an ordered map. We don't need the order, so using an unordered map will yield faster code. The example above with a single active cell on a 10×10 board took significantly longer than a second with an ordered map.)
Not sure about how you did it - and you should really always post code here - but let's try to optimize things here.
First of all, there is not really a difference between that and a quadratic grid. Different neighbor relationships, but I mean, that is just a small translation function. If you have a problem there, we should treat this separately, maybe on CodeReview.
Now, the naive solution is:
for all fields
count neighbors
if odd: add a marker to update to one, else to zero
for all fields
update all fields by marker of former step
this is obviously in O(N). Iterating twice is somewhat twice the actual run time, but should not be that bad. Try not to allocate space every time that you do that but reuse existing structures.
I'd propose this solution:
at the start:
create a std::vector or std::list "activated" of pointers to all fields that are activated
each iteration:
create a vector "new_activated"
for all items in activated
count neighbors, if odd add to new_activated
for all items in activated
set to inactive
replace activated by new_activated*
for all items in activated
set to active
*this can be done efficiently by putting them in a smart pointer and use move semantics
This code only works on the activated fields. As long as they stay within some smaller area, this is far more efficient. However, I have no idea when this changes - if there are activated fields all over the place, this might be less efficient. In that case, the naive solution might be the best one.
EDIT: after you now posted your code... your code is quite procedural. This is C++, use classes and use representation of things. Probably you do the search for neighbors right, but you can easily make mistakes there and therefore should isolate that part in a function, or better method. Raw arrays are bad and variables like n or k are bad. But before I start tearing your code apart, I instead repeat my recommendation, put the code on CodeReview, having people tear it apart until it is perfect.
This started off as a comment, but I think it could be helpful as an answer in addition to what has already been stated.
You stated the following limitations:
1 <= R <= 10, 1 <= C <= 10
Given these restrictions, I'll take the liberty to can represent the grid/matrix M of R rows and C columns in constant space (i.e. O(1)), and also check its elements in O(1) instead of O(R*C) time, thus removing this part from our time-complexity analysis.
That is, the grid can simply be declared as bool grid[10][10];.
The key input is the large number of turns k, stated to be in the range:
1 <= k <= 2^(63) - 1
The problem is that, AFAIK, you're required to perform k turns. This makes the algorithm be in O(k). Thus, no proposed solution can do better than O(k)[1].
To improve the speed in a meaningful way, this upper-bound must be lowered in some way[1], but it looks like this cannot be done without altering the problem constraints.
Thus, no proposed solution can do better than O(k)[1].
The fact that k can be so large is the main issue. The most anyone can do is improve the rest of the implementation, but this will only improve by a constant factor; you'll have to go through k turns regardless of how you look at it.
Therefore, unless some clever fact and/or detail is found that allows this bound to be lowered, there's no other choice.
[1] For example, it's not like trying to determine if some number n is prime, where you can check all numbers in the range(2, n) to see if they divide n, making it a O(n) process, or notice that some improvements include only looking at odd numbers after checking n is not even (constant factor; still O(n)), and then checking odd numbers only up to √n, i.e., in the range(3, √n, 2), which meaningfully lowers the upper-bound down to O(√n).
Problem description:
There's a chocolate bar that consists of m x n squares. Some of the squares are black, some are white. Someone breaks the chocolate bar along its vertical axis or horizontal axis. Then it is broken again along its vertical or horizontal axis and it's being broken until it can broken into a single square or it can broken into squares that are only black or only white. Using a preferably divide-and-conquer algorithm, find the number of methods a chocolate bar can be broken.
Input:
The first line tells you the m x n dimensions of the chocolate bar. In the next m lines there are n characters that tell you how does the chocolate bar look. Letter w is a white square, letter b is a black square.
for example:
3 2
bwb
wbw
Output:
the number of methods the chocolate bar can be broken:
for the example above, it's 5 (take a look at the attached picture).
I tried to solve it using an iterative approach. Unfortunately, I couldn't finish the code as I'm not yet sure how to divide the the halves (see my code below). I was told that an recursive approach is much easier than this, but I have no idea how to do it. I'm looking for another way to solve this problem than my approach or I'm looking for some help with finishing my code.
I made two 2D arrays, first for white squares, second for black squares. I'm making a matrix out of the squares and if there's a chocolate of such or such color, then I'm marking it as 1 in the corresponding array.
Then I made two arrays of the two cumulative sums of the matrices above.
Then I created a 4D array of size [n][m][n][m] and I made four loops: first two (i, j) are increasing the size of an rectangular array that is the size of the searching array (it's pretty hard to explain...) and two more loops (k, l) are increasing the position of my starting points x and y in the array. Then the algorithm checks using the cumulative sum if in the area starting at position kxl and ending at k+i x l+j there is one black and one white square. If there is, then I'm creating two more loops that will divide the area in half. If in the two new halves there are still black and white squares, then I'm increasing the corresponding 4D array element by the number of combinations of the first halve * the number of combinations of the second halve.
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
int counter=0;
int n, m;
ifstream in;
in.open("in.txt");
ofstream out;
out.open("out.txt");
if(!in.good())
{
cout << "No such file";
return 0;
}
in >> n >> m;
int whitesarray[m][n];
int blacksarray[m][n];
int methodsarray[m][n][m][n];
for(int i=0; i<m; i++)
{
for(int j=0; j<n; j++)
{
whitesarray[i][j] = 0;
blacksarray[i][j] = 0;
}
}
while(in)
{
string colour;
in >> colour;
for (int i=0; i < colour.length(); i++)
{
if(colour[i] == 'c')
{
blacksarray[counter][i] = 1;
}
if(colour[i] == 'b')
{
whitesarray[counter][i] = 1;
}
}
counter++;
}
int whitessum[m][n];
int blackssum[m][n];
for (int i=0; i<m; i++)
{
for (int j=0; j<n; j++)
{
if(i-1 == -1 && j-1 == -1)
{
whitessum[i][j] = whitesarray[i][j];
blackssum[i][j] = blacksarray[i][j];
}
if(i-1 == -1 && j-1 != -1)
{
whitessum[i][j] = whitessum[i][j-1] + whitesarray[i][j];
blackssum[i][j] = blackssum[i][j-1] + blacksarray[i][j];
}
if(j-1 == -1 && i-1 != -1)
{
whitessum[i][j] = whitessum[i-1][j] + whitesarray[i][j];
blackssum[i][j] = blackssum[i-1][j] + blacksarray[i][j];
}
if(j-1 != -1 && i-1 != -1)
{
whitessum[i][j] = whitessum[i-1][j] + whitessum[i][j-1] - whitessum[i-1][j-1] + whitesarray[i][j];
blackssum[i][j] = blackssum[i-1][j] + blackssum[i][j-1] - blackssum[i-1][j-1] + blacksarray[i][j];
}
}
}
int posx=0;
int posy=0;
int tempwhitessum=0;
int tempblackssum=0;
int k=0, l=0;
for (int i=0; i<=m; i++)
{
for (int j=0; j<=n; j++) // wielkosc wierszy
{
for (posx=0; posx < m - i; posx++)
{
for(posy = 0; posy < n - j; posy++)
{
k = i+posx-1;
l = j+posy-1;
if(k >= m || l >= n)
continue;
if(posx==0 && posy==0)
{
tempwhitessum = whitessum[k][l];
tempblackssum = blackssum[k][l];
}
if(posx==0 && posy!=0)
{
tempwhitessum = whitessum[k][l] - whitessum[k][posy-1];
tempblackssum = blackssum[k][l] - blackssum[k][posy-1];
}
if(posx!=0 && posy==0)
{
tempwhitessum = whitessum[k][l] - whitessum[posx-1][l];
tempblackssum = blackssum[k][l] - blackssum[posx-1][l];
}
if(posx!=0 && posy!=0)
{
tempwhitessum = whitessum[k][l] - whitessum[posx-1][l] - whitessum[k][posy-1] + whitessum[posx-1][posy-1];
tempblackssum = blackssum[k][l] - blackssum[posx-1][l] - blackssum[k][posy-1] + blackssum[posx-1][posy-1];
}
if(tempwhitessum >0 && tempblackssum > 0)
{
for(int e=0; e<n; e++)
{
//Somehow divide the previously found area by two and check again if there are black and white squares in this area
}
for(int r=0; r<m; r++)
{
//Somehow divide the previously found area by two and check again if there are black and white squares in this area
}
}
}
}
}}
return 0;
}
I strongly recommend recursion for this. In fact, Dynamic Programming (DP) would also be very useful, especially for larger bars. Recursion first ...
Recursion
Your recursive routine takes a 2-D array of characters (b and w). It returns the number of ways this can be broken.
First, the base cases: (1) if it's possible to break the given bar into a single piece (see my comment above, asking for clarification), return 1; (2) if the array is all one colour, return 1. For each of these, there's only one way for the bar to end up -- the way it was passed in.
Now, for the more complex case, when the bar can still be broken:
total_ways = 0
for each non-edge position in each dimension:
break the bar at that spot; form the two smaller bars, A and B.
count the ways to break each smaller bar: count(A) and count(B)
total_ways += count(A) * count(B)
return total_ways
Is that clear enough for the general approach? You still have plenty of coding to do, but using recursion allows you to think of only the two basic ideas when writing your function: (1) How do I know when I'm done, and what trivial result do I return then? (2) If I'm not done, how do I reduce the problem?
Dynamic Programming
This consists of keeping a record of situations you've already solved. The first thing you do in the routine is to check your "data base" to see whether you already know this case. If so, return the known result instead of recomputing. This includes the overhead of developing and implementing said data base, probably a look-up list (dictionary) of string arrays and integer results, such as ["bwb", "wbw"] => 5.
I was trying to do this question i came across while looking up interview questions. We are asked the number of ways of placing r coins on a n*m grid such that each row and col contain at least one coin.
I thought of a backtracking solution, processing each cell in the grid in a row major order, I have set up my recursion in this way. Seems my approach is faulty because it outputs 0 every time. Could someone please help me find the error in my approach. ? Thanks.
constraints. n , m < 200 and r < n*m;
Here is the code i came up with.
#include<cstdio>
#define N 201
int n, m , r;
int used[N][N];
int grid[N][N] ; // 1 is coin is placed . 0 otherwise. // -1 undecided.
bool isOk()
{
int rows[N];
int cols[N];
for(int i = 0 ; i < n ; i++) rows[i] = 0;
for(int i = 0 ; i < m ; i++) cols[i] = 0;
int sum = 0;
for(int i = 0 ; i < n ; i++)for(int j = 0; j < m ; j++)
{
if(grid[i][j]==1)
{
rows[i]++;
cols[j]++;
sum++;
}
}
for(int i = 0 ; i < n ; i++)
{
if(rows[i]==0) return false;
}
for(int j = 0 ; j < n ; j++)
{
if(cols[j]==0) return false;
}
if(sum==r) return true;
else return false;
}
int calc_ways(int row , int col, int coins)
{
if(row >= n) return 0;
if(col >= m) return 0;
if(coins > r) return 0;
if(coins == r)
{
bool res = isOk();
if(res) return 1;
else 0;
}
if(row == n - 1 and col== m- 1)
{
bool res = isOk();
if(res) return 1;
else return 0;
}
int nrow, ncol;
if(col + 1 >= m)
{
nrow = row + 1;
ncol = 0;
}
else
{
nrow = row;
ncol = col + 1;
}
if(used[row][col]) return calc_ways(nrow, ncol, coins);
int ans = 0;
used[row][col] = 1;
grid[row][col] = 0;
ans += calc_ways(nrow , ncol , coins);
grid[row][col] = 1;
ans += calc_ways(nrow , ncol , coins + 1);
return ans;
}
int main()
{
int t;
scanf("%d" , &t);
while(t--)
{
scanf("%d %d %d" , &n , &m , &r);
for(int i = 0 ; i <= n ; i++)
{
for(int j = 0; j <= m ; j++)
{
used[i][j] = 0;
grid[i][j] = -1;
}
}
printf("%d\n" , calc_ways(0 , 0 , 0 ));
}
return 0;
}
You barely need a program to solve this at all.
Without loss of generality, let m <= n.
To begin with, we must have n <= r, otherwise no solution is possible.
Then, we subdivide the problem into a square of size m x m, on to which we will place m coins along the major diagonal, and a remainder, on to which we will place n - m coins so as to fulfil the remaining condition.
There is one way to place the coins along the major diagonal of the square.
There are m^(n - m) possibilities for the remainder.
We can permute the total so far in n! ways, although some of those will be duplicates (how many is left as an exercise for the student).
Furthermore, there are r - n coins left to place and (m - 1)n places left to put them.
Putting these all together we have an upper bound of
1 x m^(n - m) x n! x C((m - 1)n, r - n)
solutions to the problem. Divide this number by the number of duplicate permutations and you're done.
Problem 1
The code will start by placing a coin on each square and marking each square as used.
It will then test the final position and decide that the final position does not meet the goal of r coins.
Next it will start backtracking, but will never actually try another choice because used[row][col] is set to 1 and this shortcircuits the code to place coins.
In other words, one problem is that entries in "used" are set, but never cleared during the recursion.
Problem 2
Another problem with the code is that if n,m are of size 200, then it will never complete.
The issue is that this backtracking code has complexity O(2^(n*m)) as it will try all possible combinations of placing coins (many universe lifetimes for n=m=200...).
I would recommend you look at a different approach. For example, you might want to consider dynamic programming to compute how many ways there are of placing "k" coins on the remaining "a" columns of the board such that we make sure that we place coins on the "b" rows of the board that currently have no coins.
It can be treated as total ways in which d grid can b filled with r coins -(total ways leaving a single row nd filling in d rest -total ways leaving a single column nd filling in d rest- total ways leaving a row nd column together nd filling d rest) which implies
p(n*m ,r) -( (p((n-1)*m , r) * c(n,1)) +(p((m-1)*n , r) * c(m,1))+(p((n-1)*(m-1) , r) * c(n,1)*c(m,1)) )
I just think so but not sure of it!
I've been thinking about this and I just can't think of a way to fill in a matrix with an outward spiral, so that I can do the following:
Turn this:
1 2 3 4 5 ... n
To
21 22 23 24 25 26
20 07 08 09 10 27
19 06 01 02 11 28
18 05 04 03 12 29
17 16 15 14 13 30
...n
My problem is the algorithm itself, but if instead of pseudocode you can help with C++, that'd be better.
This is some code I wrote to test things out, but I really don't know how I can go about to do this.
#include <stdio.h>
#include <string>
using namespace std;
int main() {
//int n = 5;
int spiral[5][6];
for (int i = 0; i < 5; i++)
for (int u = 0; u < 6; u++)
spiral[i][u] = 0;
spiral[2][2] = 1;
string direction = "right";
for (int i = 2; i < 5; i++) {
for (int u = 2; u < 6; u++) {
if (direction == "right") {
spiral[i][u + 1] = spiral[i][u] + 1;
direction = "down";
}
}
}
for (int i = 0; i < 5; i++) {
for (int u = 0; u < 6; u++) {
printf("%02d ", spiral[i][u]);
}
printf("\n");
}
return 0;
}
Thank you!
You can make the observation that there are similar squares with the lowest value in the bottom-left position then going upwards, right, down and left.
You can use this to create such a function:
template <typename Array>
void spiral_square(Array& a, int x, int y, int side, int& value)
{
int mx = x+side-1, my=y+side-1;
for (int i = 1; i <= side-1; ++i) a[my-i][x] = value++;
for (int i = 1; i <= side-1; ++i) a[y][x+i] = value++;
for (int i = 1; i <= side-1; ++i) a[y+i][mx] = value++;
for (int i = 1; i <= side-1; ++i) a[my][mx-i] = value++;
}
See it in action: http://ideone.com/9iL1F
Start at the last number, and go inwards from a corner. Move in one direction, and when you hit a wall, turn left 90-degrees.
I think ipc's solution is based on the assumption you always want to fill out an entire matrix. What if you want to do n = 28 (ie having some incomplete row or column)?
For a generic n solution, I found it easiest to start from the starting point and increment outwards knowing the pattern of travel. Notice that you go:
1 right,
1 down,
2 left,
2 up,
3 right,
3 down,
4 left,
4 up,
etc
So basically the pattern is you travel right, down, left, up for a number of steps that increments every two direction changes.
Unfortunately, I have not programmed in c++ in a while, so I did it in Ruby.
def output_spiral(n)
#For formatting, determine the length of the largest number
max_number_length = n.to_s.length
#Determine matrix size
max_x = Math.sqrt(n).floor
max_y = Math.sqrt(n).floor
if max_x * max_y < n
max_x += 1
if max_x * max_y < n
max_y += 1
end
end
#The a matrix of the required size.
#Note that for simplicity in printing spiral is an array of row arrays.
spiral = Array.new
row = Array.new(max_x){ |i| ' ' }
max_y.times{ spiral << row.clone }
#Determine the starting point index (ie where to insert 1)
x = ((max_x-1)/2).floor
y = ((max_y-1)/2).floor
#Input the start point value, formatted to the right size
spiral[y][x] = "%0#{max_number_length}d" % 1
#Setup counters required to iterate through the spiral
steps_in_direction = 1 #This defines how many steps to take in a direction
steps_count = 0 #This defines how many steps have been taken in the direction
direction = 'right' #This defines the direction currently travelling
steps_in_direction_count = 0 #This define how many times we have used the same steps_in_direction value
#Iterate through all the numbers up to n
2.upto(n) do |i|
#Change index based on the direction we are travelling
case direction
when 'right' then x += 1
when 'down' then y += 1
when 'left' then x -= 1
when 'up' then y -= 1
end
#Input the value, formatted to the right size
spiral[y][x] = "%0#{max_number_length}d" % i
#Increment counters
steps_count += 1
if steps_count == steps_in_direction
steps_count = 0
steps_in_direction_count += 1
if steps_in_direction_count == 2
steps_in_direction += 1
steps_in_direction_count = 0
end
case direction
when 'right' then direction = 'down'
when 'down' then direction = 'left'
when 'left' then direction = 'up'
when 'up' then direction = 'right'
end
end
end
#Output spiral
spiral.each do |x|
puts x.join(' ')
end
end
output_spiral(95)
See http://ideone.com/d1N2c, which does a spiral of n=95.
I'm going to assume this is for project euler #28 (I just did this problem the other day). The secret isn't in creating the matrix, but in realizing the pattern. Realize the pattern and you can just count the two diagonals out without creating the matrix.
1, 3, 5, 7, 9, 13, 17, 21, 25, ... , n
Skipping anything?
As far as recreating the spiral matrix, I think the best way would be to work backwards after figuring out the pattern. Start from n and work your way down to 1. It would be a lot easier to place 'n' than 1 in the matrix.
Edited:
It isn't too difficult to create the matrix after determining the diagonals (problem 28). I placed those values into the matrix and then "walked" the matrix filling in all of the other values based on the main diagonal values that I had previously filled into the matrix. However, I waste a small amount of time determining the two main diagonals. I like IPC's solution better. However, just as another method, here is the code to compute the matrix after I have determined the two main diagonals. Let n refer to the size of the grid, for example, 5.
int[,] t = new int[n, n];
int sizeOf = n - 1;
//Note that nums is the array of the two diagonals, which are already in sorted order based on my solution to problem 28.
//fill in diagonals
for (int diagNum = numsCount, i = sizeOf, j = 0; ; i--, j++)
{
if (diagNum < 3)
{
t[i, j] = 1;
break;
}
t[i, i] = nums[diagNum--];
t[i, j] = nums[diagNum--];
t[j, j] = nums[diagNum--];
t[j, i] = nums[diagNum--];
}
//finish filling in matrix
for (int i = sizeOf, c = 0; i > 1; i--, c++)
{
for (int j = i - 1; j > sizeOf - i; j--)
t[i, j] = t[i, i] - i + j;
for (int j = c + 1; j < sizeOf - c; j++)
t[c, j] = t[c, c] - j + c;
for (int j = c + 1; j < i; j++)
t[j, i] = t[c, i] - j + c;
for (int j = i - 1; j > c; j--)
t[j, c] = t[i, c] - i + j;
}
#include<stdio.h>
main()
{
long int i,j,k,a,b,c,d,sum1=0,sum2=0,sum3=0,sum4=0;
for(i=1;i<=500;i++)
{
a=(2*i+1)*(2*i+1);
sum1=sum1+a;
b=a-2*i;
sum2=sum2+b;
c=b-2*i;
sum3=sum3+c;
d=c-2*i;
sum4=sum4+d;
}`
printf("%ld",sum1+sum2+sum3+sum4+1);``
}