Waterfall Rock Hit Counter - c++

I'm having a difficulity in solving a problem from my class, it's about dynamic programming (or so my professor called it). The problem is called Waterfall Rock Hit. (Time limit : 1s, Memory Limit : 16mb)
We're given the upper left (v1, h1) and lower right coordinate (v2, h2) of the rock and we simulate a waterfall and count number of rock hit by the water, imagine the water started falling from a coordinate (x,y), it will fall to (x-1, y) and continue to fall until it hit a rock. when it hit a rock, the water will split to the right and left, and follow the length of the rock, here's the a picture of how the algorithm will work.
Simulation Picture.
What we need to watch here, if the rock was hit more than once, the problem also guaranteed there won't any rock stick to each other, and the water will always find a way through any 2 rocks.
Here's a piece of my incomplete code, where i still thinking of the second condition for when the water hit the rock and preventing double count.
int maks=0, n, m, nstone;
struct a{
int v1, v2, h1, h2; //coordinates
bool pass; //passed or not?
}; a arr[5000];
bool acompare(a lhs, a rhs){
return lhs.v1 < rhs.v1; //compare height descending
}
int fall(int x, int y){
if (x == n || y == m || y == -1) //if the water passed the wall
return 0;
else if () //the confusing condition if the water hit the rock
return 1 + fall(x, h1-1) + fall(x, h2+1));
else // if there's nothing below
return fall(x-1, y);
}
int main(){
cin>> n>> m>> nstone; //waterfall size (n*m) and number of stone
for (int i=0; i<nstone; i++){ //read the stone's corner
cin>> arr[i].v1>> arr[i].h1>> arr[i].v2>> arr[i].h2;
arr[i].pass = false;
}
sort(arr, arr+nstone, acompare); //sort the stone's based on height
cin>> start; //read the start point of the water
cout<< fall(start, m)<< endl;
return 0;
}
testcase sample input :
6 6 3
2 3 2 4
4 2 5 2
5 5 6 5
output :
3

First, the condition you have trouble with. It's inefficient to iterate all rocks on each step, even binary search is not optimal. This can be solved by a table, like in a board game. Create a NxM 2D array for this (e.g. 4 bytes each item = 250000 * 4 bytes = 2MB, far away from your 16MB limit) and mark all points covered by rocks. On each step you'll need to check a single point if it's a rock.
Secondly, it's a DP problem because streams can merge like the one in the bottom middle:
..|..
.|X|.
.|.|.
|X|X|
|.|.|
Your approach would calculate this stream twice. (BTW, I don't see where you use your bool pass; //passed or not? member) Once calculated store the number of rocks the stream has hit in your board game table, e.g. in your example:
.1331.
.1XX1.
010.1.
0X0010
0X00X0
0.00X0
So next time you reach already calculated point of a stream you already know how many rocks you hit from this point.

I see that you don't use std::vector and use C-style array instead. I would assume that you're not familiar with C++ STL library and hence will provide an answer that uses as little of C++ STL as possible.
Because there are multiple stones to check, you need to use a loop (or std::find_if) to check all of them.
for(int stone_index=0;stone_index<nstone;++stone_index)
For each stone, check if the (x,y) coordinate is right on the top of that stone.
Once you've found one, it's guaranteed that you won't found any other ones (because stones don't touch), so just return immediately.
return 1 + fall(x, h1-1) + fall(x, h2+1));
(this is just pseudocode, replace h1 and h2 with suitable values)
If you reach the end of the loop without finding a stone,
// if there's nothing below
return fall(x-1, y);
Note that this solution requires nstone steps to check, you can do better using a std::map or something. That may be too hard for you.

Related

How to calculate expected number of turns using DP in O(n)?

A single-player board game. The board is made up of a row of n cells numbered 1 to n from left to
right. Cell ‘j' contains a positive integer cj.
The rules are like this:
You start on the leftmost cell.
On each turn, you roll a fair 6-sided die with A as the outcome number. You
move forward A × cj cells, where j is the index of the cell that you are standing
on.
You win once you exit the board i.e., you win when your index j > n.
For instance, consider the board of size n=10
To begin with, you are at the first cell having the value c1 = 2. In the first turn, you roll a dice
and obtain a value 1, so you move forward 2 cells. Then on the next roll you roll a 5 on cell 3
(with c3 = 4), so you move forward 20 cells makes you exit the board. You win!! You took 2
turns to win.
How to calculate the expected number of turns needed to win using dynamic programming algorithm that runs in time (n) for the above game?
The recurrence relation you're looking for is:
E[j] = 0 (if j > n)
E[j] = 1 + 1/6 * sum_k(E[j + k * c_j]) (otherwise, for k \in 1..6)
For each cell, calculate how many turns to win on average.
For cell[k] with k>=n, this is 0.
For other cells with k<n, it 1 plus the average of turns to win at cell[1..6*c_k].
Cache results and don't recalculate them.
Return turns to win from cell 0.
Yes, this is seemingly nothing non-obvious. Dynamic programming is seeming to do nothing non-obvious, with an appropriately bounded cache in the middle of the naive algorithm.
The trick is arranging the problem to have a cache with good bounds that makes a naive algorithm collapse into not doing much work.

Tiling a 2xM array with 2x1 tiles to maximise the differences - INOI 2008, P2

(As I am new and may not be aware of the code of conduct, feel free to edit this post to make this better and more helpful to other people.)
Greetings everybody!
This problem is related to this: Problem Link
The problem in brief:
Given a 2xM array and we want to tile it with 2x1 tiles such that the sum of absolute values of the differences of the values "covered" via the individual tiles is maximized. We want to report this max sum.
The problem in detail:
In Domino Solitaire, you have a grid with two rows and many columns. Each square in the grid contains an integer. You are given a supply of rectangular 2×1 tiles, each of which exactly covers two adjacent squares of the grid. You have to place tiles to cover all the squares in the grid such that each tile covers two squares and no pair of tiles overlap. The score for a tile is the difference between the bigger and the smaller number that are covered by the tile. The aim of the game is to maximize the sum of the scores of all the tiles.
Below is my code for it. Basically, I've done a sort of a recursive thing because there are two cases: (1) One vertical 2x1 tile in the start and (2) Two horizontal 2x1 laid together to cover 2 columns.
#include <bits/stdc++.h>
using namespace std;
int maxScore(int array[][2], int N, int i);
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
int N; cin >> N;
int array[N][2]; for(int i=0;i<N;i++) cin >> array[i][0] >> array[i][1];
cout << maxScore(array, N, 0);
return 0;
}
int maxScore(int array[][2], int N, int i){
int score1 = abs(array[i][0] - array[i][1]) + maxScore(array, N, i+1);
int score2 = abs(array[i][0] - array[i+1][0]) + abs(array[i][1] - array[i+1][1]) + maxScore(array, N, i+2);
return max(score1, score2);
}
However, this seems to be a very inefficient solution and I can't really understand how to cover the base cases (otherwise this would go on forever).
Any help would be really appreciated. Thank You! (BTW I want to create a new tag - Competitive Programming, can anybody help me do so?)
Maintain an array of the best solutions, where the value in column i of the array is the best solution considering only the matching colums of the input matrix. Then arr[i] = max possible by adding either one tile to the arr[i-1] solution, or 2 to the arr[i-2] solution. Treat arr[-1] as 0 and set arr[0] to the val of one vertical dominoe.
This is intentionally not a complete solution, but should help you find a much faster implementation.
Since you need to cover every square of a 2xM grid, there is no way you have dominoes placed like this:
. . .[#|#]. .
. .[#|#]. . .
So essentially, for every sub-block the right most domino is vertical, or there are two horizontal ones above each other.
If you start from the left, you only need to remember what your best result was for the first n or n-1 tiles, then try placing a vertical domino right to the n-solution or two horizontal dominoes right to the n-1 solution. The better solution is the best n+1 solution. You can compute this in a simple for-loop, as a first step, store all partial solutions in a std::vector.

Get minimum number of shots required so that goals over shots is the percentage given

I am having some difficulty understanding why an extremely simple program I've coded in C++ keeps looping. I'll describe the problem at hand first just to check if maybe my solution is incorrect and then I'll write the code:
The shooting efficiency of a soccer player is the percentage of
goals scored over all the shots on goal taken in all his professional career. It is a rational number between 0 and 100,
rounded to one decimal place. For example, a player who
made 7 shots on goal and scored 3 goals has a shooting
efficiency of 42.9.
Given the shooting efficiency of a player, we want to know which
is the minimum amount of shots on goal needed to get that
number (which must be greater than 0).
What I thought of is that if p is the percentage given, then in order to get the minimum number of shots n, the relationship np <= n must be satisfied since np would be the number of goals scored over a total of n.
I've coded the following program:
int main(){
float efficiency;
cin >> efficiency;
int i = 1;
float tries = i*efficiency;
while(tries > i){
i++;
tries = i*efficiency;
}
cout << i << endl;
return 0;
}
This program never terminates since it keeps looping inside the while, any suggestions on what might be wrong would be really appreciated.
You multiply efficiency after incrementing i. This means efficiency will grow much faster than i as when i increases by 1, efficiency will increase (i+1) times, ending up much larger than i.

Minimum cuts with each cut passing through 2 points on circle

There are N persons and we wishes to give only one piece of cake to each person. Bob has his own way of maximizing number of pieces. For each cut, he tries to make maximum possible smaller pieces after that cut. The cake is circular and each cut follows a straight line that passes through the circle twice. There will be no half-cuts or semi-cuts.
what is the minimum number of cuts he should make so that every person gets at least one smaller part of the cake.
(With this kind of distribution, every person will not get same size of cake and he is not bothered of it.)
Example : Let N=3 then answer is 2.
Note : Passes through circle twice mean that the cut doesn't stop in between. It starts at one point on circle, and ends at some other point. It is not necessary that cut has to pass through center for sure
Here is my code that I tried :
typedef unsigned long long int ulld;
ulld n;
cin >> n;
ulld steps = 0;
ulld currentAmount = 1;
while (currentAmount < n) steps++, currentAmount <<= 1;
cout << steps << endl;
N can go upto 10^12. So I want O(log n) appraoch.
The number of pieces f(k) that can be made with k cuts is a somewhat famous problem, whose solution is f(k) = k*(k+1)/2 + 1. You could have found that sequence yourself by working small examples and invoking the search function on OEIS. Solving for f(k) = n, we get k = ceil((sqrt(8*n - 7) - 1)/2).

Help with geometry problem - don't have any idea

I am preparing myself for programming competitions and i would like to know how can i solve this problem. I guess it's geometry problem, and it seems i can't get any ideas about solving it.
Here it is:
There is a yard in which there are wolves and sheep. In the yard there are also blocks which do not allow to pass. The wolves are represented with 'w' and the sheep with 's', while the blocks are with '#' and the space where everyone can move is '.' . So a possible input will look like:
8 8
.######.
#..s...#
#.####.#
#.#w.#.#
#.#.s#s#
#s.##..#
#.w..w.#
.######.
The 2 numbers above the yard are rows x columns.
As you can see, by this there can be formed sectors of different kind in the yard. Here are two sectors:
####
#.w#
####
#s.#
In the first one there is a wolf and in the second a sheep. Because they are placed in two different sectors (i.e. the wolf can't get to the sheep), he can't eat it. If they were in a same sector, the wolf would eat the sheep.
My question for you is this: Given an input like the ones above, how should i calculate how many sheep will survive ? How can i represent the 'yard' in c++ ? How should the algorithm looks like ? Are there any materials for understanding similar problems and issues ?
Any help is appreciated. Thank you in advance.
This problem is basically a problem of finding connected sub-graphs (aka components) for a given graph.
You can solve the problem by representing each "non-block" coordinate as a graph node, linking the 2 neighboring coordinates in a graph. Then find connected subgraphs using BFS (or any other algorithm suitable for the topic - I'm sure any web page or Wiki on graph algos will have a list of assorted algorithms on that.
Once you have your subgraphs, just find which subgraphs have zero wolves (by finding which subgraph each wolf coordinate is on), and count sheep in those subgraphs .
Hope this is enough for you to start.
What you are looking for here is to find the connected components of the graph, then you just need to count the number of wolves and sheep in each one.
using namespace std;
int w, h;
cin >> w >> h;
vector<string> grid(h);
for (int i = 0; i < h; ++i)
cin >> grid[i];
vector< vector<bool> > seen(h, vector<bool>(w, false));
int survived = 0;
const int mx[] = {-1, 0, 1, 0}, my[] = {0, -1, 0, 1};
for (int i = 0; i < h; ++i)
for (int j = 0; j < w; ++j)
if (!seen[i][j] && grid[i][j] != '#')
{
int sheep = 0, wolves = 0;
typedef pair<int, int> point;
stack<point> s;
s.push(point(i, j));
while (!s.empty())
{
point p = s.top();
int x = p.first, y = p.second;
if (grid[x][y] == 'w') wolves++;
if (grid[x][y] == 's') sheep++;
for (int k = 0; k < 4; ++k)
{
int x2 = x + mx[k], y2 = y + my[k];
if (x2<0 || x2>=h || y2<0 || y2>=w) continue;
if (grid[x2][y2] == '#' || seen[x2][y2]) continue;
s.push(point(x2, y2));
}
}
survived += max(0, sheep - wolves);
}
cout << "Surviving sheep = " << survived << endl;
Running time and memory usage is optimal at O(rows x columns).
Note that code is untested, but I believe this should work.
A simple approach would be to do a flood fill starting on each wolf. You can assume that each wolf will move (flood fill) the dots around him. After you flood fill starting from all the dots, any remaining sheep will survive.
In your example:
####
#.w#
####
#s.#
would fill to:
####
#fw#
####
#s.#
(I used f for the filled space), and the algorithm will stop, so s will survive.
maybe try thinking of the yard as a group of sectors. when creating a sector, if there is a wolf in it, remove all sheep. Now the only challenge is representing a sector, which seems much more manageable.
Consider using the logic of flood filling algorithms.
Doesn't look like a geometry problem to me. I would solve it with the Flood fill algorithm
Fill every area with a unique number. Then, for every number you filled an area with, find out how many sheep and how many wolves are adjacent to that number. The only surviving sheep are those that are adjacent to a number k that no wolves are adjacent to.
You can represent the matrix in C++ as a matrix of chars: char A[maxrows][maxcols]. However, to use flood fill, I would use a matrix of ints, because you might have more areas than the max value of a char.
Is this a time-limited competition? E.g., one where your score is a function of the number of programs solved in a given time?
For these I would recommend a simple approach based on two things:
Represent the data as a 2D array
Determine when sheep and wolves share a sector by searching connectivity, using something like a flood-fill algorithm from each wolf. I would recommend starting from the wolves and "killing off" sheep when you reach them. After you do this for each wolf, any remaining sheep in the data structure survive.
The key in the time-limited competitions is to come up with a simple solution that's quick to program. Modern computers are extremely fast. Don't think about geometric algorithms unless you need to be able to handle vast data sets, just think how could I throw computation at the problem to solve it easily.
While I thought about this several other people suggested flood-filling, so this is somewhat redundant.