Help with geometry problem - don't have any idea - c++

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.

Related

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.

Waterfall Rock Hit Counter

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.

Finding the sequence so that the event is finished at the earliest

This is a problem from informatica olympiad that I am trying to solve since sometime. This is important for me since this contains an underlying fundamental problem that I see in a lot of problems.
Given N citizens for an event such that they have to program on a single computer, eat chocolates and then eat doughnuts. time , ith citizen takes for each task is given as input. Each citizen has to finish the tasks in order, i.e., first program then eat chocolate and then eat doughnuts. Any number of people could eat chocolates or doughnuts at a time but since computer is one only 1 person can program each time. Once, he is done he would move to chocolates and next person shall program. The task is to find the order in which citizens be sent out to program such that event ends in minimum time and this time is the output.
I worked this problem using the approach:
If I start with ith citizen then for remaining n-1 citizens if I find the time (tn-1) then tn = max((ni[0]+ni[1]+ni[2]), ni[0] + tn-1). Eg.:
18 7 6
23 10 27
20 9 14
then 18+7+6, 18+23+10+27, 18+23+20+9+14, max would be 84 but if you start with 23 then time would be 74 which is less.
I implemented this approach whose code I am presenting here. However, the complexity is O(n!) for my approach. I can see underlying repeated subproblems,so I could use DP approach. But the problem is I need to store the time value for each list i to j such that it could begin with any k from i to j and so on. This storage process would again be complex and require n! storage. How, to solve this problem and similar such problems?
Here is my program on my approach:
#include <iostream>
#include <vector>
#include <climits>
int min_time_sequence(std::vector<std::vector<int> > Info, int N)
{
if (N == 0) return 0;
if (N == 1)
{
int val = Info[0][0] + Info[0][1] + Info[0][2];
return val;
}
std::vector<std::vector<int> > tmp = Info;
int mn = INT_MAX;
for (int i = 0; i < N; ++i)
{
//prepare new list
tmp.erase(tmp.begin()+i);
int mn = min_time_sequence(tmp, N-1);
int v1 = Info[i][0] + mn;
int v2 = Info[i][0] + Info[i][1] + Info[i][2];
int larger = v1 > v2 ? v1 : v2;
if (mn > larger) mn = larger;
}
return mn;
}
int main()
{
int N;
std::cin>>N;
std::vector<std::vector<int> > Info;
//input
for (int i = 0; i < N; ++i)
{
std::cin>>Info[i][0];
std::cin>>Info[i][1];
std::cin>>Info[i][2];
}
int mx = 0;
if (N > 0)
mx = min_time_sequence(Info, N);
std::cout<<mx<<std::endl;
return 0;
}
Since you asked for general techniques, you might want to look at greedy algorithms, that is, algorithms that repeatedly optimize the next selection. In this case, that might be for the remaining person who will take the longest total time (the sum of the three times) to program next, so he or she will finish eating sooner, and no one who starts later will take more time.
If such an algorithm were optimal, the program could simply sort the list by the sum of times, in decreasing order, which takes O(N log N) time.
You would, however, be expected to prove that your solution is valid. One way to do that is known as “Greedy Stays Ahead.” That is an inductive proof where you show that the solution your greedy algorithm produces is at least as optimal (by some measure equivalent to optimality at the final step) at its first step, then that it is also as good at its second step, the step after that, and so on. Hint: you might try measuring what is the worst-case scenario for how much time the event could need after each person starts programming. At the final step, when the last person gets to start programming, this is equivalent to optimality.
Another method to prove an algorithm is optimal is “Proof by Exchange.” This is a form of proof by contradiction in which you hypothesize that some different solution is optimal, then you show that exchanging a part of that solution with a part of your solution could improve the supposedly-optimal solution. That contradicts the premise that it was ever optimal—which proves that no other solution is better than this. So: assume the optimal order is different, meaning the last person who finishes started after someone else who took less time. What happens if you switch the positions of those two people?
Greedy solutions are not always best, so in cases where they are not, you would want to look at other techniques, such as symmetry-breaking and pruning the search tree early.

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).

Read in a matrix and build a graph

I have a rectangular room; its' floor is coverd with floor boards, some of them are broken.
The dimensions of the room are N and M: 1 <=N,M<=300.
I read N and M from stdin, and then I read N strings of length M, which look like this:
..**.***....*.**...**.***
.**......**...***..***...
and so on, where . is a good floor board and * is a broken one.
I intend to replace the broken floor boards with new one, and I only have two types of those: two-by-ones and one-by-ones. I can't cut the two-by-ones into two one-by-ones.
To find a way to do this, I paint the floor like a checkerboard, so that the halves of a broken two-by-one are of different color.
Then I mean to build a bipartite graph (consisting of a white and a black part) from the resulting matrix, and I'd like to build and analyse it with this code.
What's the best way to do that?
I think that I shouldn't keep all the matrix in memory (since it can be rather large). Ideally I should be able to read in strings and update the graph on the run.
EDIT:
My code should like this:
int main()
{
int N, M;
std::cin >> N;
assert (( N >=1) && (N <=300));
std::cin >> M;
assert (( M >=1) && (M <=300));
for (int i = 0; i < N; ++i)
std::cin >> // that's where I have to read the string
//...and the next string
// use these 2 strings to update a graph
// with prGraph.AddEdge()
return 0;
}
If it is really so important not to store the entire matrix in memory, you can read it line by line and store only the current and the previous line because it is sufficient to construct a graph properly.
A naive graph construction using an adjacency matrix would take 300x300 ^2, which is tough to fit in memory.
You can take advantage of the fact that each vertex can have at most 4 edges - you would only need space on order of 300 x 300 x 4 using adjacency lists for your maxflow instead, as long as you change the graph traversal accordingly.