Partition Frisbees C++ - c++

We have a set F of n frisbee's in 2D. We want to partition F into two subsets F1, and F2 so that no two frisbee's intersect in each respective subset. Our function takes in input as so: (x_j, y_j) is the centre of the j-th frisbee, and rad_j is the radius of the j-th frisbee. The output should be s_0 s_1 ... s_n-1, where s_j = 1 if the j-th frisbee is in F1 and s_i = 2 if the j-th frisbee is in F2. If you cannot partition F, just return 0. Ideally, the algo should be computed in O(n^2) time.
I figured that I should use some type type of matrix representation of this like graph, but then I don't think I need need to construct a graph, but I think I BFS/DFS would be useful, but I'm stuck on how exactly to do this elegantly in O(n^2). I am coding this in C++ by the way.

You were on a right track with a graph search. Here's a C++11, O(V^2), depth first search solution that uses O(V+E) space.
The DFS itself is O(V+E) in time, but generating the adjacency lists is O(V^2) the obvious way.
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
struct Frisbee
{
double x;
double y;
double radius;
};
int dfs(const vector< vector<int> > &adj, vector<int> &p, int last_ind, int curr_ind)
{
if (p[curr_ind]) // node already painted
{
if (p[last_ind] == p[curr_ind]) // painted same color as neighbor -> failure
return 0;
return 1; // painting is compatible
}
// node not yet painted
p[curr_ind] = (1 == p[last_ind] ? 2 : 1); // paint opposite color as neighbor
for (int j = 0; j < adj[curr_ind].size(); ++j)
if (!dfs(adj, p, curr_ind, adj[curr_ind][j])) // dfs on neighbors
return 0;
return 1;
}
int partition(const vector<Frisbee> &F, vector<int> &p)
{
// compute adjacency lists
vector< vector<int> > adj(F.size());
p.resize(F.size());
for (int i = 0; i < F.size(); ++i)
{
p[i] = 0;
for (int j = i + 1; j < F.size(); ++j)
{
double dist = sqrt((F[i].x - F[j].x) * (F[i].x - F[j].x) + (F[i].y - F[j].y) * (F[i].y - F[j].y));
if (dist < F[i].radius + F[j].radius)
{
adj[i].push_back(j);
adj[j].push_back(i);
}
}
}
// find starting points for dfs
for (int i = 0; i < F.size(); ++i)
if (0 == p[i]) // node i not yet painted
{
p[i] = 1; // arbitrarily choose initial color
for (int j = 0; j < adj[i].size(); ++j)
if (!dfs(adj, p, i, adj[i][j])) // dfs on neighbors
return 0;
}
return 1;
}
int main(int argc, char **argv)
{
vector<Frisbee> F = { { 1.0, 1.0, 1.0 }, { 2.0, 2.0, 1.0 }, { -1.0, -1.0, 1.0 }, { -2.0, -2.0, 1.0 }, { 5.0, 5.0, 1.0 }, { -5.0, 5.0, 1.0 } };
vector<int> p;
if (partition(F, p))
{
for (size_t i = 0; i < F.size(); ++i)
cout << p[i] << " ";
cout << endl;
}
else
cout << "No partition possible!" << endl;
F.push_back({ 1.5, 1.5, 1.0 }); // add a 3-way intersection
if (partition(F, p))
{
for (size_t i = 0; i < F.size(); ++i)
cout << p[i] << " ";
cout << endl;
}
else
cout << "No partition possible!" << endl;
return 0;
}
Here's the output (of two partitions on slightly different sets of Frisbee's):
1 2 1 2 1 1
No partition possible!

Shouldn't you just do a stacked for-loop and use the distance formula? i.e. two intersect if the distance between their centres is smaller than the sum of their radii.
After that, you've state-exploded it and then you can proceed to just do loop inclusion/exclusion (i.e. include everything and get rid of all invalid ones and then include as many valid ones etc.)

You can build a graph where an edge means "touches". Then you can use a bipartition algorithm on that graph. Boost.Graph contains one.
http://www.boost.org/doc/libs/1_57_0/libs/graph/doc/is_bipartite.html
The algorithm is O(V+E), i.e. worst case O(V^2) if all discs touch each other (although there's a good chance it will abort early in that case).
Building the graph naively is O(V^2), since you have to check each disc against all others, although you might be able to optimize the common case by building a geographical quad tree to sort the discs first.

Related

Compiler optimization on the traveling salesman problem

I am playing with the travelling salesman problem and am looking at the version where:
the towns are points in 2d space and there are paths from every town to all others and the lengths are the distances between the points. So it's very easy to implement the naive solution where you check all permutations of n points and calculate the length of the path.
I've found however that for n >= 10 the compiler does some magic and prints a value that is certainly not the actual shortest path. I compile with the Microsoft visual studio compiler in release mode with the default settings. For values (10,30) it thinks for 30 seconds and then returns some number that seems like it could be correct but it is not (I check in different ways). And for n > 40 it calculates a result immediately and is always 2.14748e+09.
I am looking for an explanation to what does the compiler do in the different situations (the (10,30) case is really interesting). And an example where these optimizations are more useful than the program just spinning to the end of the world.
vector<pair<int,int>> points;
void min_len()
{
// n is a global variable with the number of points(towns)
double min = INT_MAX;
// there are n! permutations of n elements
for (auto j = 0; j < factorial(n); ++j)
{
double sum = 0;
for (auto i = 0; i < n - 1; ++i)
{
sum += distance_points(points[i], points[i + 1]);
}
if (sum < min)
{
min = sum;
s_path = points;
}
next_permutation(points.begin(), points.end());
}
for (auto i = 0; i < n; ++i)
{
cout << s_path[i].first << " " << s_path[i].second << endl;
}
cout << min << endl;
}
unsigned int factorial(unsigned int n)
{
int res = 1, i;
for (i = 2; i <= n; i++)
res *= i;
return res;
}
Your factorial function is overflowing. Try replacing it with one returning int64_t and see your code taking 3 years to terminate for n > 20.
constexpr uint64_t factorial(unsigned int n) {
return n ? n * factorial(n-1) : 1;
}
Also, you don't need to calculate this at all. The std::next_permutation function returns 0 when all permutations have occured (starting from sorted position).

C++: I don't know how to solve the timeout in the problem of comparing coordinates in the coordinate plane

Up to 100,000 coordinates are entered. Only coordinates corresponding to specific conditions should be output. If there are coordinates with larger x values ​​and smaller y values ​​than each coordinate, the corresponding coordinates are excluded from the output list.
My English is not good, so I'm giving some examples.
[input] First enter the number of coordinates N to be input. and enter the coordinates.
[output] The coordinate numbers corresponding to the condition are output in ascending order.
p2 is not correct
p4 is correct
[input example]
6
1 3
6 6
7 3
8 2
8 6
2 1
[output example]
4
5
6
The time limit is 500ms.
[timeout input example]
50000
1 1
1 2
1 3
... skip
1 49999
1 50000
[timeout output example]
1 1
1 2
1 3
... skip
1 49999
1 50000
coordinates image:
The following problem was solved with a simple loop, but a timeout occurs when 100,000 values ​​are entered. I don't know which algorithm to use.
I also attach the C++ source code I wrote.
Also, I tried using the sort function, but when the number of N is small, it works fine, and when the number of N is large, it cannot be compared properly. I guess I couldn't write the compare function properly.
So I tried writing the source code without using sort.
I thought and corrected it over two days, but I couldn't solve it, so I seek help. thanks for reading.
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main() {
int N;
cin >> N;
bool* visible = new bool[N];
for (int i = 0; i < N; i++)visible[i] = true;
vector<pair<int,pair<int, int>>> v;
for (int i = 0; i < N; i++) {
int a, b;
cin >> a >> b;
v.push_back(make_pair(i,make_pair(a, b)));
}
for (int i = 0; i < v.size(); i++) {
if (visible[i] == false)
continue;
for (int j = 0; j < v.size(); j++) {
if (visible[i] == true &&visible[j]==true && v[i].second.first < v[j].second.first && v[i].second.second > v[j].second.second) {
visible[i] = false;
break;
}
else if (visible[i] == true && visible[j] == true && v[i].second.first > v[j].second.first && v[i].second.second < v[j].second.second) {
visible[j] = false;
continue;
}
}
}
for (int i = 0; i < v.size(); i++) {
if (visible[i] == true)
cout << v[i].first + 1 << endl;
}
return 0;
}
[Source code that tried to sort but failed]
#include <iostream>
#include <algorithm>
#include <vector>
#include <tuple>
using namespace std;
bool* visible;
int compare(pair<int, pair<int, int>> n1, pair<int, pair<int, int>> n2) {
pair<int, int> a = n1.second, b = n2.second;
bool swap = false;
if (a.first > b.first && a.second < b.second) {
visible[n2.first - 1] = false;
swap = true;
}
else if (a.first < b.first && a.second > b.second) {
visible[n1.first - 1] = false;
//swap = true;
}
cout << "[" << n1.first << "]" << a.first << ", " << a.second << " vb : " << visible[n1.first - 1] << " :\t[" << n2.first << "]" << b.first << ", " << b.second << "vb : " << visible[n2.first - 1] << "\t";
cout << "swap: " << swap << endl;
return swap;
}
int main() {
int N;
cin >> N;
visible = new bool[N];
for (int i = 0; i < N; i++)visible[i] = true;
vector<pair<int, pair<int, int>>> v;
for (int i = 0; i < N; i++) {
int a, b;
cin >> a >> b;
v.push_back(make_pair(i+1, make_pair(a, b)));
}
sort(v.begin(), v.end(), compare);
for (int i = 0; i < v.size(); i++)
cout << "p" << v[i].first << " : " << v[i].second.first << ", " << v[i].second.second <<"\t"<< visible[v[i].first-1]<< endl;
return 0;
}
In this case, p4 moves to (4,2). In this case, p3,4,5,6 becomes the correct answer.
I'm not totally sure this works for every corner case, but the idea is here. It took me a while to nail it down, probably because the problem description wasn't exactly clear. Basically you want to mark as not visible the points for which it is possible to find another one with a larger x and a smaller y, i.e. the points which have another on their lower right.
If you sort your points on x, then you only need to check those with a larger index.
In fact, we are interested only in the one with the minimum y, because it will dominate all others.
That value can only decrease while moving from right to left, so we just need to keep track of the minimum y. The only problem is how to deal with points that have the same x, because they could have a lower y before a higher one, rendering valid points non visible. The trick is to make sure that when browsed from right to left (higher indices to lower ones) the y will decrease. So when sorting, if x is equal we will sort on y.
#include <iostream>
#include <algorithm>
#include <vector>
int main()
{
struct point {
int x, y;
bool visible = true;
};
size_t N;
std::cin >> N;
std::vector<point> v(N);
std::vector<size_t> idx(N);
for (size_t i = 0; i < N; ++i) {
auto& p = v[i];
idx[i] = i;
std::cin >> p.x >> p.y;
}
sort(idx.begin(), idx.end(), [&v](const size_t& a, const size_t& b) {
if (v[a].x == v[b].x)
return v[a].y < v[b].y;
return v[a].x < v[b].x;
});
int miny = INT_MAX;
for (size_t i = N; i-- > 0;) {
auto& p = v[idx[i]];
miny = std::min(miny, p.y);
if (p.y > miny) {
p.visible = false;
}
}
for (size_t i = 0; i < N; ++i) {
auto& p = v[i];
if (p.visible) {
std::cout << i + 1 << '\n';
}
}
return 0;
}
Given two points A and B, there are three possible configurations:
A makes B invisible
B makes A invisible
None of the above
The "makes-invisible" relation between the points is not strict weak ordering required by std::sort, so calling std::sort with a comparison function that implements this relation is undefined.
I understood two things from your code, so I'll list both the solutions:
I: This is a basic example of a modified 'Longest Increasing Subsequence'.
Let's first consider the coordinates as something different, let's say , the coordinate (x,y), would become the ractangle with height (x) and width (y) (consider this as if we were making rectangles with corners (0,0) (x,0) (0,y) (x,y)).
If we need 'ascending' points, it means that their areas overlap. More formally, if the list of point we need is A(1),A(2),A(3),...,A(k), then for each i in range 1..k-1, A(i).x<A(i+1).x and A(i).y<A(i+1).y.
You can find an optimal solution using this
Note: the coordinates should be sorted. By what criteria? Well, as long as the longest increasing subsequence would appear after a sorting of that criteria, then it's correct.
II: This is a basic example of finding the convex hull.
The convex hull of a polygon would be the convex polygon (with the most nodes) , whose set of coordinates is included in the set of the coordinates of the original polygon. I recommend reading this . After finding the upper half, you can apply a mentality as described in the previous example, although you must find a substring instead of a subsequence, so that would make the complexity O(nlog+n)
Hope this was helpful

Rotating matrix by 90 degress in anticlockwise direction , where am i going wrong

Given a square matrix mat[ ][ ] of size N x N. The task is to rotate it by 90 degrees in anti-clockwise direction without using any extra space. Problem Link
My Logic - for a matrix N x N, rotate the outer window in an anticlockwise direction by swapping elements starting from left column -> bottom row -> right column -> top row using temp variable X-1 time where X is the dimension of the outer window. I don't know why it's not working. Please Help me spot the problem.
#include<bits/stdc++.h>
using namespace std;
int main() {
int t=1; cin>>t;
while (t--) {
int n; cin>>n; vector<vector<int>>a(n,vector<int>(n));
for(int i=0;i<n;i++) for(int j=0;j<n;j++) cin>>a[i][j];
for(int k=0;k<n;k++) {
int i=k, j=0, p=n-1-k, q=p-i, temp;
while (q-- && i<p) {
temp=a[i][i];j=i;
while (j<=p) {
swap(temp, a[j][i]);j++;
}j=i+1;
while (j<=p) {
swap(temp, a[p][j]);j++;
}j=p-1;
while (j>=i) {
swap(temp, a[j][p]); j--;
}j=p-1;
while (j>=i) {
swap(temp, a[i][j]); j--;
}
}
}
for(int i=0;i<n;i++) {
for(int j=0;j<n;j++) cout<<a[i][j]<<" ";
cout<<"\n";
}
cout<<"\n";
}
}
Thank You
I would like to suggest an approach that looks more simpler.
Let's assume that you have a vector of vectors of the type char like this.
a b c d
e f g h
i j k l
m n o p
The result vector must look like
d h l p
c g k o
b f j n
a e i m
The result vector can be built in two steps.
In the first step the rows of the source vector are swapped.
m n o p
i j k l
e f g h
a b c d
In the second step there are swapped elements relative to the side diagonal that is for example 'm' is swapped with 'd', 'n' is swapped with 'h' and 'o' is swapped with 'l'. Then these operations are repeated for element of the second row the second column from the end of the vector.
Here is a demonstrative program.
#include <iostream>
#include <utility>
#include <vector>
int main()
{
std::vector<std::vector<char>> a =
{
{ 'a', 'b', 'c', 'd' },
{ 'e', 'f', 'g', 'h' },
{ 'i', 'j', 'k', 'l' },
{ 'm', 'n', 'o', 'p' },
};
auto n = a.size();
for ( const auto &row : a )
{
for ( const auto &item : row )
{
std::cout << item << ' ';
}
std::cout << '\n';
}
std::cout << '\n';
for ( size_t i = 0; i < n / 2; i++ )
{
std::swap( a[i], a[n-i-1] );
}
for ( const auto &row : a )
{
for ( const auto &item : row )
{
std::cout << item << ' ';
}
std::cout << '\n';
}
std::cout << '\n';
for ( size_t i = 0; i + 1 < n; i++ )
{
for ( size_t j = 0; j + i + 1 < n; j++ )
{
std::swap( a[i][j], a[n-j -1][n - i -1]);
}
}
for ( const auto &row : a )
{
for ( const auto &item : row )
{
std::cout << item << ' ';
}
std::cout << '\n';
}
std::cout << '\n';
return 0;
}
The program output is
a b c d
e f g h
i j k l
m n o p
m n o p
i j k l
e f g h
a b c d
d h l p
c g k o
b f j n
a e i m
[Note: my previous solution uses extra memory, this one doesn't. So, I've deleted the previous solution and totally updated it to provide the new one].
Well, this problem can be solved easily if we are able to use extra space, but that is not the case. Anyway, it can also be solved easily without using another extra space.
At first, let me explain my solution for this problem. Then, I'll tell you about the wrong doing in your code. My solution is similar to your approach. It considers the input array as layers of rings or loops. See below:
0 0 0 0 0
0 1 1 1 0
0 1 2 1 0
0 1 1 1 0
0 0 0 0 0
The outer ring is the 0's, the inner ring is the 1's and so on...
Now, for arguments sake, let's assume we're using extra space b(we won't use this space in solution though). Also, let us assume, b is the solved array that contains the rotated matrix. Then, we may say:
b[(n + n - j - 1) % n][i] = a[i][j] // for any i, j
// here "n" is dimension of matrix
// "i", represents ith indexed row of a
// "j", represents jth indexed column of a
// if you having problem, how this thing just dropped from sky, then
// just write down in paper, for some index (x, y) what it becomes when it is rotated
// you'll see some formula like I've described above
Okay, now, if you're clear with the formula, let me describe how this helps to solve problem:
In the previous ring figure(the one I've used for showing rings), you can see that the corner elements of the 0's rings just changed with each other, i.e. the corner elements just swap places with each other when the matrix rotated, they never interfere with other elements. This is also, true for other elements too. There is always four elements in a group, and they just swap position with each other! There's only one exception is the center(if n is odd). And the center never changes position...
If you've also, observed the loop/group of four elements, those just swap position with each other, then we can just find out the next element's position from present element's position and place the present element's value and we're done... So, how do find out next position's value. Notice, we've already talked about it, how b's result is calculated from a. So, we may write something below:
pair<int, int> getNext(pair<int, int> x, int n) {
return make_pair((n + n - x.second - 1) % n, x.first);
}
Now, come to rings, how many are there, that we should care about, well it's (n/2) rings. So, we'll just go to each ring, iterate through the elements of the first row of each ring(except the last one, cause it's included in the corner) and run a loop of four to replace the value properly in position. The full code is given below:
#include <iostream>
#include <string>
#define N 128
// returns next postition based on present position
// next position means where the present position value should
// be transferred after rotation
pair<int, int> getNext(pair<int, int> x, int n) {
return make_pair((n + n - x.second - 1) % n, x.first);
}
int main() {
int a[N][N];
int n;
scanf("%d", &n);
for(int i=0; i<n; i++) {
for(int j=0; j<n; j++) {
scanf("%d", &a[i][j]);
}
}
for(int h = 0; h < (n / 2); h++) {
int s = h;
int e = n - h - 1;
for(int k = s; k < e; k++) {
auto p = make_pair(s, k); // row = s, and col = k
int t = a[p.first][p.second];
for(int c=0; c<4; c++) {
auto p2 = getNext(p, n);
int temp = a[p2.first][p2.second];
a[p2.first][p2.second] = t;
t = temp;
p = p2;
}
}
}
for(int i=0; i<n; i++) {
for(int j=0; j<n; j++) {
printf("%d ", a[i][j]);
}
printf("\n");
}
return 0;
}
Now, what is wrong with your code:
I guess, you've already understood, that your algo is not correct...and the implementation is buggy too...
[P.S.]: pls, don't just copy paste the code, first understand it. Also, write code in a manner, so other's can read...and if any error you find with the algo I've provided or you may have problem with understanding any concept, let me know in the comment...

Given n numbers, writing a routine to find the largest number between 4 consecutive numbers

I am trying to figure out how to find the largest from the first four numbers in a sequence, then find the largest in the next four numbers in the sequence, etc...
I wrote a function that finds the largest element in an array which is here:
double max_array(int n, double array[]){
double arr[n];
arr[0] = 0;
double max;
for(int i = 0; i < n; i++)
{
if(arr[0] < array[i])
arr[0] = array[i];
}
max = arr[0];
return max;
}
I believe I can use what I have done here to write a routine to do the latter of that I described but I am not sure how to do this. Perhaps I have to write an entirely new function but I am not sure, any suggestions are greatly appreciated.
This should more or less do what you want. There are multiple results, one for each quad you have in the input array:
#include <valarray>
#include <cassert>
std::valarray<double> maxQuads(std::valarray<double> input) {
assert(!(input.size() % 4)); // The input must contain a multiple of 4 values
std::valarray<double> output(input.size() / 4);
for(std::size_t sliceIndex = 0; sliceIndex + 4 < input.size(); sliceIndex += 4) {
std::slice slice(sliceIndex, 4, 1);
output[sliceIndex / 4] = std::valarray(input[slice]).max();
}
return output;
}
void test() {
double aTestArray[] = {1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5};
std::valarray results = maxQuads(std::valarray(aTestArray, 8));
std::cout << "Max of the first 4: " << results[0];
std::cout << "Max of the second 4: " << results[1];
}
Well, you could reuse max_array:
// Assume I have an array 'foo' with N elements.
// In your code, N should be an actual value, like 10, and NOT a variable.
double V[N/4];
int i = 0;
while (i+4 < N) {
// use the i-th element of foo as the 0-th
// element of 'array' in max_array.
double V[i/4] = max_array(4, &(foo[i]));
i += 4;
}
Please note that, with the above code, if N is not a multiple of 4, say, N = 6, then the last elements will not be taken into account.
For example, if foo is equal to { 0.0, 1.0, 1.5, 2.1, 5.0, 10.3 }, then V will only have one element. { 2.1 }.
if u want to use the function you already have you can do it this way
create another function that calls the function you already have.
double* max_array_vec(int n, double array[]){
int max_mumber = n/4 + (n%4); // how many max number you will have
double max[max_number];
double temp[4];
arr[0] = 0;
for(int i = 0; i < max_number; i++)
{
std::copy(array+ (3 * i), array+ (3 * (i + 1)), temp);
max[i] = max_array(4,temp);
}
max = arr[0];
return max;
}
but you can make another function that does the entire process and it can be much easier.
Edited second part
double *max_array(int n, double *array){
double arr[n/4 + 1] = {-1000, } ;// since ur looking for the biggest number u should initialize tis array with numbers really small like -400 or something like that
int index = 0;
for(int i = 0; i < n; i++)
{
if(i%4 == 0 && i!= 0)
index++;
if(arr[index] < array[i])
arr[index] = array[i];
}
//printf("\n");
//for(int i = 0; i < 4; i++)
//printf("%f\n ", arr[i]);
return arr;
}
the problem was in the fist time i wasnt ignoring when i = 0 that i dont need to increment the index

Shortest path in a grid between two points. With a catch

I have this problem where I have to find the shortest path in an NxM grid from point A (always top left) to point B (always bottom right) by only moving right or down. Sounds easy, eh? Well here's the catch: I can only move the number shown on the tile I'm sitting on at the moment. Let me illustrate:
2 5 1 2
9 2 5 3
3 3 1 1
4 8 2 7
In this 4x4 grid the shortest path would take 3 steps, walking from top left 2 nodes down to 3, and from there 3 nodes right to 1, and then 1 node down to the goal.
[2] 5 1 2
9 2 5 3
[3] 3 1 [1]
4 8 2 [7]
If not for the shortest path, I could also be taking this route:
[2] 5 [1][2]
9 2 5 3
3 3 1 [1]
4 8 2 [7]
That would unfortunately take a whopping 4 steps, and thus, is not in my interest.
That should clear things out a bit. Now about the input.
The user inputs the grid as follows:
5 4 // height and width
2 5 2 2 //
2 2 7 3 // the
3 1 2 2 // grid
4 8 2 7 //
1 1 1 1 //
Homework
I have thought this through, but cannot come to a better solution than to simplify the inputted grid into an unweighed (or negative-weight) graph and run something like dijkstra or A* (or something along those lines) on it. Well... this is the part where I get lost. I implemented something to begin with (or something to throw to thrash right away). It's got nothing to do with dijkstra or A* or anything; just straight-forward breadth-first search.
The Code
#include <iostream>
#include <vector>
struct Point;
typedef std::vector<int> vector_1D;
typedef std::vector< std::vector<int> > vector_2D;
typedef std::vector<Point> vector_point;
struct Point {
int y, x;
vector_point Parents;
Point(int yPos = 0, int xPos = 0) : y(yPos), x(xPos) { }
void operator << (const Point& point) { this->Parents.push_back(point); }
};
struct grid_t {
int height, width;
vector_2D tiles;
grid_t() // construct the grid
{
std::cin >> height >> width; // input grid height & width
tiles.resize(height, vector_1D(width, 0)); // initialize grid tiles
for(int i = 0; i < height; i++) //
for(int j = 0; j < width; j++) // input each tile one at a time
std::cin >> tiles[i][j]; // by looping through the grid
}
};
void go_find_it(grid_t &grid)
{
vector_point openList, closedList;
Point previous_node; // the point is initialized as (y = 0, x = 0) if not told otherwise
openList.push_back(previous_node); // (0, 0) is the first point we want to consult, of course
do
{
closedList.push_back(openList.back()); // the tile we are at is good and checked. mark it so.
openList.pop_back(); // we don't need this guy no more
int y = closedList.back().y; // now we'll actually
int x = closedList.back().x; // move to the new point
int jump = grid.tiles[y][x]; // 'jump' is the number shown on the tile we're standing on.
if(y + jump < grid.height) // if we're not going out of bounds
{
openList.push_back(Point(y+jump, x)); //
openList.back() << Point(y, x); // push in the point we're at right now, since it's the parent node
}
if(x + jump < grid.width) // if we're not going out of bounds
{
openList.push_back(Point(y, x+jump)); // push in the new promising point
openList.back() << Point(y, x); // push in the point we're at right now, since it's the parent node
}
}
while(openList.size() > 0); // when there are no new tiles to check, break out and return
}
int main()
{
grid_t grid; // initialize grid
go_find_it(grid); // basically a brute-force get-it-all-algorithm
return 0;
}
I should probably also point out that the running time cannot exceed 1 second, and the maximum grid height and width is 1000. All of the tiles are also numbers from 1 to 1000.
Thanks.
Edited Code
#include <iostream>
#include <vector>
struct Point;
typedef std::vector<int> vector_1D;
typedef std::vector< std::vector<int> > vector_2D;
typedef std::vector<Point> vector_point;
struct Point {
int y, x, depth;
vector_point Parents;
Point(int yPos = 0, int xPos = 0, int dDepth = 0) : y(yPos), x(xPos), depth(dDepth) { }
void operator << (const Point& point) { this->Parents.push_back(point); }
};
struct grid_t {
int height, width;
vector_2D tiles;
grid_t() // construct the grid
{
std::cin >> height >> width; // input grid height & width
tiles.resize(height, vector_1D(width, 0)); // initialize grid tiles
for(int i = 0; i < height; i++) //
for(int j = 0; j < width; j++) // input each tile one at a time
std::cin >> tiles[i][j]; // by looping through the grid
}
};
int go_find_it(grid_t &grid)
{
vector_point openList, closedList;
Point previous_node(0, 0, 0); // the point is initialized as (y = 0, x = 0, depth = 0) if not told otherwise
openList.push_back(previous_node); // (0, 0) is the first point we want to consult, of course
int min_path = 1000000;
do
{
closedList.push_back(openList[0]); // the tile we are at is good and checked. mark it so.
openList.erase(openList.begin()); // we don't need this guy no more
int y = closedList.back().y; // now we'll actually move to the new point
int x = closedList.back().x; //
int depth = closedList.back().depth; // the new depth
if(y == grid.height-1 && x == grid.width-1) return depth; // the first path is the shortest one. return it
int jump = grid.tiles[y][x]; // 'jump' is the number shown on the tile we're standing on.
if(y + jump < grid.height) // if we're not going out of bounds
{
openList.push_back(Point(y+jump, x, depth+1)); //
openList.back() << Point(y, x); // push in the point we're at right now, since it's the parent node
}
if(x + jump < grid.width) // if we're not going out of bounds
{
openList.push_back(Point(y, x+jump, depth+1)); // push in the new promising point
openList.back() << Point(y, x); // push in the point we're at right now, since it's the parent node
}
}
while(openList.size() > 0); // when there are no new tiles to check, break out and return false
return 0;
}
int main()
{
grid_t grid; // initialize grid
int min_path = go_find_it(grid); // basically a brute-force get-it-all-algorithm
std::cout << min_path << std::endl;
//system("pause");
return 0;
}
The program now prints the correct answer. Now I have to optimize (run time is way too big). Any hints on this one? Optimizing is the one thing I suck at.
The Answer
In the end the solution appeared to consist of little code. The less the better, as I like it. Thanks to Dejan Jovanović for the beautiful solution
#include <iostream>
#include <vector>
#include <algorithm>
struct grid_t {
int height, width;
std::vector< std::vector<int> > tiles;
std::vector< std::vector<int> > distance;
grid_t() // construct the grid
{
std::cin >> height >> width; // input grid height & width
tiles.resize(height, std::vector<int>(width, 0)); // initialize grid tiles
distance.resize(height, std::vector<int>(width, 1000000)); // initialize grid tiles
for(int i = 0; i < height; i++) //
for(int j = 0; j < width; j++) // input each tile one at a time
std::cin >> tiles[i][j]; // by looping through the grid
}
};
int main()
{
grid_t grid; // initialize grid
grid.distance[0][0] = 0;
for(int i = 0; i < grid.height; i++) {
for(int j = 0; j < grid.width; j++) {
if(grid.distance[i][j] < 1000000) {
int d = grid.tiles[i][j];
if (i + d < grid.height) {
grid.distance[i+d][j] = std::min(grid.distance[i][j] + 1, grid.distance[i+d][j]);
}
if (j + d < grid.width) {
grid.distance[i][j+d] = std::min(grid.distance[i][j] + 1, grid.distance[i][j+d]);
}
}
}
}
if(grid.distance[grid.height-1][grid.width-1] == 1000000) grid.distance[grid.height-1][grid.width-1] = 0;
std::cout << grid.distance[grid.height-1][grid.width-1] << std::endl;
//system("pause");
return 0;
}
There is need to construct the graph, this can easily be solved with dynamic programming using one scan over the matrix.
You can set the distance matrix D[i,j] to +inf at the start, with D[0,0] = 0. While traversing the matrix you just do
if (D[i,j] < +inf) {
int d = a[i, j];
if (i + d < M) {
D[i + d, j] = min(D[i,j] + 1, D[i + d, j]);
}
if (j + d < N) {
D[i, j + d] = min(D[i,j] + 1, D[i, j + d]);
}
}
The final minimal distance is in D[M -1, N-1]. If you wish to reconstruct the path you can keep a separate matrix that marks where the shortest path came from.
You're overthinking it. :) Run a Breadth-First Search. The solution space is a binary tree, where each node branches into "right" or "down". From current point, generate the down point and right point, stuff their coordinates into a queue, repeat until at finish.
Without checking, something like this:
queue = [{ x: 0, y: 0, path: [] }] # seed queue with starting point
p = nil
do
raise NoSolutionException if p.empty? # solution space exhausted
p = queue.pop # get next state from the back of the queue
break if p.x == MAX_X - 1 && p.y == MAX_Y - 1 # we found final state
l = grid[p.x][p.y] # leap length
# add right state to the front of the queue
queue.unshift({x: p.x + l, y: p.y, path: p.path + [p] }) if p.x + l <= MAX_X
# add down state to the front of the queue
queue.unshift({x: p.x, y: p.y + l, path: p.path + [p] }) if p.y + l <= MAX_Y
end
puts p.path
Uglifying into C++ left as exercise for the reader :p
Build an unweighted directed graph:
There are NxM vertices. In what follows, vertex v corresponds to grid square v.
There is an arc from vertex u to v iff you can jump from grid square u to square v in a single move.
Now apply a shortest path algorithm from the top-right vertex to the bottom-left.
Finally, observe that you don't actually need to build the graph. You can simply implement the shortest path algoritm in terms of the original grid.
Start off with a brute force approach to get it to work, then optimize from there. The brute force is straight-forward: run it recursively. Take your two moves, recurse on those, and so on. Collect all the valid answers and retain the minimum. If the run time is too long, then you can optimize by a variety of means. For instance, some of the moves may be invalid (because they exceed a dimension of the grid) and can be eliminated, and so on. Keep optimizing until a worst case input runs at the desired speed.
Having said that, the performance requirements only make sense if you are using the same system and inputs, and even then there are some caveats. Big O notation is a much better way of analyzing the performance, plus it can point you to an algorithm and eliminate the need for profiling.