i am doing a standard problem to calculate min moves to reach target by a knight but i also want to keep track of path but its showing error.it dispalys
prog.cpp: In function
'int minStepToReachTarget(int*, int*, int)':
prog.cpp:76:42: error: no match for 'operator[]' (operand types are
'std::vector<cell>' and 'cell')
{q.push(cell(x, y, t.dis + 1));parent[cell(x, y, t.dis + 1)]=t;}
I have commented down the line 76 in my code.
struct cell {
int x, y;
int dis;
cell() {}
cell(int x, int y, int dis): x(x), y(y), dis(dis) {}
};
//cell parent[10000];
typedef cell c;
vector<c> parent(10000);
bool isInside(int x, int y, int N) {
if (x >= 1 && x <= N && y >= 1 && y <= N)
return true;
return false;
}
int minStepToReachTarget(int knightPos[], int targetPos[], int N) {
// x and y direction, where a knight can move
int dx[] = {-2, -1, 1, 2, -2, -1, 1, 2};
int dy[] = {-1, -2, -2, -1, 1, 2, 2, 1};
// queue for storing states of knight in board
queue<cell> q;
// push starting position of knight with 0 distance
q.push(cell(knightPos[0], knightPos[1], 0));
cell t;
int x, y;
bool visit[N + 1][N + 1];
// make all cell unvisited
for (int i = 1; i <= N; i++)
for (int j = 1; j <= N; j++)
visit[i][j] = false;
visit[knightPos[0]][knightPos[1]] = true;
// parent[cell(knightPos[0], knightPos[1], 0)]=t;
// loop untill we have one element in queue
while (!q.empty()) {
t = q.front();
//parent[t]=t;
q.pop();
visit[t.x][t.y] = true;
// if current cell is equal to target cell,
// return its distance
if (t.x == targetPos[0] && t.y == targetPos[1])
return t.dis;
// loop for all reahable states
for (int i = 0; i < 8; i++) {
x = t.x + dx[i];
y = t.y + dy[i];
// If rechable state is not yet visited and
// inside board, push that state into queue
if (isInside(x, y, N) && !visit[x][y]) {
q.push(cell(x, y, t.dis + 1));
//76 ERROR: parent[cell(x, y, t.dis + 1)]=t;}
}
}
}
int main() {
// size of square board
int N = 6;
int knightPos[] = {4, 5};
int targetPos[] = {1, 1};
int m= minStepToReachTarget(knightPos, targetPos, N);
cout<<m<<endl;
return 0;
}
#Code
int dx[8] = {-1,-2, 1 ,2 ,-1, -2, 1, 2};
int dy[8] = {-2,-1, -2,-1, 2, 1, 2, 1};
q.push(ppi(pi(kx, ky), 0));
while(!q.empty()){
pi cur = q.front().first; int d = q.front().second; q.pop();
int x = cur.first;
int y = cur.second;
// printf("%d %d %d\n", x,y, visited[x][y]);
if(visited[x][y]) continue;
visited[x][y] = true;
if (x == tx && y == ty){
printf("%d", d);
return 0;
}
for(int i = 0; i<8; i++){
int nx = x+dx[i];
int ny = y+dy[i];
if(nx <= 0 || nx > n || ny <= 0 || ny > n) continue;
q.push(ppi(pi(nx, ny), d+1));
}
}
printf("-1");
Explanation
Here, this is the bfs which I implemented. I am storing the grid as a boolean value, I can keep track of which squares I have traveled too. If I am unable to reach the square, I output -1. I would also recommend not using function calls unless really necessary, as this is a simple BFS question.
Extension
Just in case you want to find out more, I took the following chunk from my code for a harder problem, where there exists a grid with forbidden squares where the knight cannot travel. In that case, forbidden squares are initially marked as 'true' instead of 'false' to signify that is traveled so I will not go on it.
I hope my above solution helps.
Related
The problem:
Given a 2D matrix consist of 0 and 1, you can only go in location with 1. Start at point (x, y), we can move to 4 adjacent points: up, down, left, right; which are: (x+1, y), (x-1, y), (x, y+1), (x, y-1).
Find a path from point (x, y) to point (s, t) so that it has the least number of turns.
My question:
I tried to solve this problem using dijsktra, it got most of the cases right, but in some cases, it didn't give the most optimal answer.
Here's my code:
pair<int,int> go[4] = {{-1,0}, {0,1}, {1,0}, {0,-1}};
bool minimize(int &x, const int &y){
if(x > y){
x = y;
return true;
}return false;
}
struct Node{
pair<int,int> point;
int turn, direc;
Node(pii _point, int _turn, int _direc){
point = _point;
turn = _turn;
direc = _direc;
}
bool operator < (const Node &x) const{
return turn > x.turn;
}
};
void dijkstra(){
memset(turns, 0x3f, sizeof turns);
turns[xHome][yHome] = -1;
priority_queue<Node> pq;
pq.push(Node({xHome, yHome}, -1, -1));
while(!pq.empty()){
while(!pq.empty() &&
pq.top().turn > turns[pq.top().point.first][pq.top().point.second])pq.pop();
if(pq.empty())break;
pii point = pq.top().point;
int direc = pq.top().direc;
pq.pop();
for(int i = 0; i < 4; i++){
int x = point.first + go[i].first ;
int y = point.second + go[i].second;
if(!x || x > row || !y || y > col)continue;
if(matrix[x][y])
if(minimize(turns[x][y], turns[point.first ][point.second] + (i != direc)))
pq.push(Node({x, y}, turns[x][y], i));
}
}
}
P/S: The main solving is in void dijkstra, the others are just to give some more information in case you guys need it.
I have found a way to solve this problem, storing directions and using BFS() to reduce the time complexity:
struct Node{
short row, col;
char dir;
Node(int _row = 0, int _col = 0, int _dir = 0){
row = _row; col = _col; dir = _dir;
}
};
void BFS(){
memset(turns, 0x3f, sizeof turns);
deque<pair<int, Node> > dq;
for(int i = 0; i < 4; i++){
Node s(xHome + dx[i], yHome + dy[i], i);
if(!matrix[s.row][s.col])continue;
turns[s.row][s.col][s.dir] = 0;
dq.push_back({0, s});
}
while(!dq.empty()){
int d = dq.front().fi;
Node u = dq.front().se;
dq.pop_front();
if(d != turns[u.row][u.col][u.dir])continue;
for(int i = 0; i < 4; i++){
Node v(u.row + dx[i], u.col + dy[i], i);
if(!matrix[v.row][v.col])continue;
if(minimize(turns[v.row][v.col][v.dir], turns[u.row][u.col][u.dir] + (i != u.dir))){
if(i == u.dir)dq.push_front({turns[v.row][v.col][v.dir], v});
else dq.push_back({turns[v.row][v.col][v.dir], v});
trace[v.row][v.col][v.dir] = u;
}
}
}
}
An obvious error in you algorithm is that to detect the length of the path start->x->y, you should store all directions to x that can form a shortest path from start to x.
For example, suppose start=(0,0),x=(1,1),y=(1,2) and there are two paths from start to x: start->(0,1)->x, start->(1,0)->x, both have the shortest length. However, start->(0,1)->x->y has two turns while start->(1,0)->x->y has only one turn. So you need to store all the directions for each node (in this case, you should store both the directions (0,1)->x and (1,0)->x in x.
Given an integer N denoting the Length of a line segment. You need to cut the line segment in such a way that the cut length of a line segment each time is either x , y or z. Here x, y, and z are integers.
After performing all the cut operations, your total number of cut segments must be maximum.
Example 1
Input:
N = 4
x = 2, y = 1, z = 1
Output: 4
Explanation:Total length is 4, and the cut
lengths are 2, 1 and 1. We can make
maximum 4 segments each of length 1.
Example 2
Input:
N = 5
x = 5, y = 3, z = 2
Output: 2
Explanation: Here total length is 5, and
the cut lengths are 5, 3 and 2. We can
make two segments of lengths 3 and 2.
This is my solution
int max_seg(int M[], int n, int x, int y, int z)
{
if( (n<=0) && (M[0] != -1) )
return M[0];
else if( (n>0) && M[n] != -1)
return M[n];
int q;
if(n <= 0)
{
q = 0;
M[0] = q;
return M[0];
}
else
{
q = max({1 + max_seg(M, n-x, x, y, z), 1 + max_seg(M, n-y, x, y, z), 1 + max_seg(M, n-y, x, y, z) });
M[n] = q;
return M[n];
}
}
int maximizeTheCuts(int n, int x, int y, int z)
{
//Your code here
int M[n+1] = {0}; // compiler does permit this
for(int i=0; i<=n; i++)
M[i] = -1;
return max_seg(M, n, x, y, z);
}
What is wrong with my code. Any help appreciated.
It failed for the test case below
N= 4000
x=3 y=4 z=5
returned 1334 instead of 1333
You'd need to ensure that max_seg is never called with a negative n, or else that, if called with negative n, it returns a value that won't be taken as the best solution. – #IgorTandetnik
fix
int max_seg(int M[], int n, int x, int y, int z)
{
if( (n<0) )
return INT_MIN;
else if( (n>=0) && M[n] != -1)
return M[n];
int q;
if(n <= 0)
{
q = 0;
M[0] = q;
return M[0];
}
else
{
q = max({1 + max_seg(M, n-x, x, y, z), 1 + max_seg(M, n-y, x, y, z), 1 + max_seg(M, n-y, x, y, z) });
M[n] = q;
return M[n];
}
}
int maximizeTheCuts(int n, int x, int y, int z)
{
//Your code here
int M[n+1] = {0}; // compiler does permit this
for(int i=0; i<=n; i++)
M[i] = -1;
return max_seg(M, n, x, y, z);
}
I am running into buffer overflow with the following solution to https://leetcode.com/problems/shortest-path-in-a-grid-with-obstacles-elimination/
class Solution {
public:
struct pt {
int x;
int y;
int k;
int s;
pt(int x, int y, int k, int s): s(s), x(x), y(y), k(k) {}
};
int shortestPath(vector<vector<int>>& grid, int k) {
int height = grid.size(), width = grid[0].size();
std::vector<std::pair<int, int>> dirs {{1,0}, {0, 1}, {-1, 0}, {0, -1}};
std::vector<std::vector<int>> maxKs(height, std::vector<int>(width, -1));
std::queue<pt> q;
q.push(pt(0, 0, k, 0));
while ( !q.empty() ) {
auto f = q.front();
q.pop();
if (f.x == width-1 && f.y == height-1) return f.s;
if (maxKs[f.x][f.y] >= f.k || f.k < 0) continue;
maxKs[f.x][f.y] = f.k;
for (auto dir : dirs) {
int x = f.x + dir.first;
int y = f.y + dir.second;
if (x < 0 || y < 0 || x == width || y == height) continue;
int curK = f.k - (grid[x][y] == 1);
if (curK < 0) continue;
q.push(pt(x,y,curK,f.s + 1));
}
}
return -1;
}
};
Wondering if anyone has ideas as to what is happening here?
You declared the size as
int height = grid.size(), width = grid[0].size();
but you are using width as the number of elements of grid and height as the number of grid[x].
maxKs[f.x][f.y] should be maxKs[f.y][f.x] and grid[x][y] should be grid[y][x].
i am writing code to solve this problem on leetcode
my strategy to solve this is:
run dfs for each cell index (x,y)
on each dfs call check if cell is a destination cell
accordingly set the flags
if both flags are true then add this cell to "ans" vector else carry on with the next dfs
class Solution {
public:
void psUtil(vector<vector<int> >&mat, int x, int y, int m, int n, int &isP, int &isA, vector<vector<int> >&vis, vector<vector<int> >&ans)
{
//check dstinations
if(x == 0 || y == 0)
{
isP = 1;
}
if(x == m || y == n)
{
isA = 1;
}
vector<int> cell(2);
cell[0] = x;
cell[1] = y;
// check both dst rched
if(isA && isP)
{
// append to ans
ans.push_back(cell);
return;
}
// mark vis
vis.push_back(cell);
int X[] = {-1, 0, 1, 0};
int Y[] = {0, 1, 0, -1};
int x1, y1;
// check feasible neighbours
for(int i = 0; i < 4; ++i)
{
x1 = x + X[i];
y1 = y + Y[i];
if(x1 < 0 || y1 < 0) continue;
if(mat[x1][y1] <= mat[x][y])
{
vector<vector<int> > :: iterator it;
vector<int> cell1(2);
cell1[0] = x1;
cell1[1] = y1;
it = find(vis.begin(), vis.end(), cell1);
if(it == vis.end());
else continue;
psUtil(mat, x1, y1, m, n, isP, isA, vis, ans);
if(isA && isP) return;
}
}
}
vector<vector<int>> pacificAtlantic(vector<vector<int>>& matrix)
{
// find dimensions
int m = matrix.size(); // rows
int n = matrix[0].size(); // cols
vector<vector<int> >ans;
// flags if rched destinations
int isP, isA;
isP = isA = 0;
// iterate for all indices
for(int x = 0; x < m; ++x)
{
for(int y = 0; y < n; ++y)
{
// visited nested vector
vector<vector<int> >vis;
psUtil(matrix, x, y, m, n, isP, isA, vis, ans);
isP = isA = 0;
}
}
return ans;
}
};
and my error on running this is
Runtime Error Message:
Line 924: Char 9: runtime error: reference binding to misaligned address 0xbebebebebebebec6 for type 'int', which requires 4 byte alignment (stl_vector.h)
Last executed input:
[[1,2,2,3,5],[3,2,3,4,4],[2,4,5,3,1],[6,7,1,4,5],[5,1,1,2,4]]
why am i getting this message and how do i fix it?
i found my error ! it was because of a missing boundary check for the newly calculated coordinate and improper boundary check for a coordinate in the beginning of psUtil.
instead of this:
if(x == m || y == n)
.
.
.
if(x1 < 0 || y1 < 0) continue;
it should be this:
if(x == m-1 || y == n-1)
.
.
.
if(x1 < 0 || y1 < 0 || x1 >= m || y1 >= n) continue;
Your method is pretty good, but maybe we can improve on the implementation a bit. Here is an accepted solution with a similar DFS method.
class Solution {
public:
int direction_row[4] = {0, 1, -1, 0};
int direction_col[4] = {1, 0, 0, -1};
void depth_first_search(vector<vector<int>> &grid, vector<vector<bool>> &visited, int row, int col, int height) {
if (row < 0 || row > grid.size() - 1 || col < 0 || col > grid[0].size() - 1 || visited[row][col])
return;
if (grid[row][col] < height)
return;
visited[row][col] = true;
for (int iter = 0; iter < 4; iter++)
depth_first_search(grid, visited, row + direction_row[iter], col + direction_col[iter], grid[row][col]);
}
vector<vector<int>> pacificAtlantic(vector<vector<int>> &grid) {
vector<vector<int>> water_flows;
int row_length = grid.size();
if (!row_length)
return water_flows;
int col_length = grid[0].size();
vector<vector<bool>> pacific(row_length, vector<bool>(col_length, false));
vector<vector<bool>> atlantic(row_length, vector<bool>(col_length, false));
for (int row = 0; row < row_length; row++) {
depth_first_search(grid, pacific, row, 0, INT_MIN);
depth_first_search(grid, atlantic, row, col_length - 1, INT_MIN);
}
for (int col = 0; col < col_length; col++) {
depth_first_search(grid, pacific, 0, col, INT_MIN);
depth_first_search(grid, atlantic, row_length - 1, col, INT_MIN);
}
for (int row = 0; row < row_length; row++)
for (int col = 0; col < col_length; col++)
if (pacific[row][col] && atlantic[row][col]) {
water_flows.push_back({row, col});
}
return water_flows;
}
};
I'm not also sure, if this would be the most efficient algorithm for the Pacific Atlantic Water Flow problem. You can check out the discussion board.
References
For additional details, you can see the Discussion Board. There are plenty of accepted solutions, explanations, efficient algorithms with a variety of languages, and time/space complexity analysis in there.
417. Pacific Atlantic Water Flow
417. Pacific Atlantic Water Flow - Discussion
I am trying to a C++ implementation of this knapsack problem using branch and bounding. There is a Java version on this website here: Implementing branch and bound for knapsack
I'm trying to make my C++ version print out the 90 that it should, however it's not doing that, instead, it's printing out 5.
Does anyone know where and what the problem may be?
#include <queue>
#include <iostream>
using namespace std;
struct node
{
int level;
int profit;
int weight;
int bound;
};
int bound(node u, int n, int W, vector<int> pVa, vector<int> wVa)
{
int j = 0, k = 0;
int totweight = 0;
int result = 0;
if (u.weight >= W)
{
return 0;
}
else
{
result = u.profit;
j = u.level + 1;
totweight = u.weight;
while ((j < n) && (totweight + wVa[j] <= W))
{
totweight = totweight + wVa[j];
result = result + pVa[j];
j++;
}
k = j;
if (k < n)
{
result = result + (W - totweight) * pVa[k]/wVa[k];
}
return result;
}
}
int knapsack(int n, int p[], int w[], int W)
{
queue<node> Q;
node u, v;
vector<int> pV;
vector<int> wV;
Q.empty();
for (int i = 0; i < n; i++)
{
pV.push_back(p[i]);
wV.push_back(w[i]);
}
v.level = -1;
v.profit = 0;
v.weight = 0;
int maxProfit = 0;
//v.bound = bound(v, n, W, pV, wV);
Q.push(v);
while (!Q.empty())
{
v = Q.front();
Q.pop();
if (v.level == -1)
{
u.level = 0;
}
else if (v.level != (n - 1))
{
u.level = v.level + 1;
}
u.weight = v.weight + w[u.level];
u.profit = v.profit + p[u.level];
u.bound = bound(u, n, W, pV, wV);
if (u.weight <= W && u.profit > maxProfit)
{
maxProfit = u.profit;
}
if (u.bound > maxProfit)
{
Q.push(u);
}
u.weight = v.weight;
u.profit = v.profit;
u.bound = bound(u, n, W, pV, wV);
if (u.bound > maxProfit)
{
Q.push(u);
}
}
return maxProfit;
}
int main()
{
int maxProfit;
int n = 4;
int W = 16;
int p[4] = {2, 5, 10, 5};
int w[4] = {40, 30, 50, 10};
cout << knapsack(n, p, w, W) << endl;
system("PAUSE");
}
I think you have put the profit and weight values in the wrong vectors. Change:
int p[4] = {2, 5, 10, 5};
int w[4] = {40, 30, 50, 10};
to:
int w[4] = {2, 5, 10, 5};
int p[4] = {40, 30, 50, 10};
and your program will output 90.
I believe what you are implementing is not a branch & bound algorithm exactly. It is more like an estimation based backtracking if I have to match it with something.
The problem in your algorithm is the data structure that you are using. What you are doing is to simply first push all the first levels, and then to push all second levels, and then to push all third levels to the queue and get them back in their order of insertion. You will get your result but this is simply searching the whole search space.
Instead of poping the elements with their insertion order what you need to do is to branch always on the node which has the highest estimated bound. In other words you are always branching on every node in your way regardless of their estimated bounds. Branch & bound technique gets its speed benefit from branching on only one single node each time which is most probable to lead to the result (has the highest estimated value).
Example : In your first iteration assume that you have found 2 nodes with estimated values
node1: 110
node2: 80
You are pushing them both to your queue. Your queue became "n2-n1-head" In the second iteration you are pushing two more nodes after branching on node1:
node3: 100
node4: 95
and you are adding them to you queue as well("n4-n3-n2-head". There comes the error. In the next iteration what you are going to get will be node2 but instead it should be node3 which has the highest estimated value.
So if I don't miss something in your code both your implementation and the java implementation are wrong. You should rather use a priority queue (heap) to implement a real branch & bound.
You are setting the W to 16, so the result is 5. The only item you can take into the knapsack is item 3 with profit 5 and weight 10.
#include <bits/stdc++.h>
using namespace std;
struct Item
{
float weight;
int value;
};
struct Node
{
int level, profit, bound;
float weight;
};
bool cmp(Item a, Item b)
{
double r1 = (double)a.value / a.weight;
double r2 = (double)b.value / b.weight;
return r1 > r2;
}
int bound(Node u, int n, int W, Item arr[])
{
if (u.weight >= W)
return 0;
int profit_bound = u.profit;
int j = u.level + 1;
int totweight = u.weight;
while ((j < n) && (totweight + arr[j].weight <= W))
{
totweight = totweight + arr[j].weight;
profit_bound = profit_bound + arr[j].value;
j++;
}
if (j < n)
profit_bound = profit_bound + (W - totweight) * arr[j].value /
arr[j].weight;
return profit_bound;
}
int knapsack(int W, Item arr[], int n)
{
sort(arr, arr + n, cmp);
queue<Node> Q;
Node u, v;
u.level = -1;
u.profit = u.weight = 0;
Q.push(u);
int maxProfit = 0;
while (!Q.empty())
{
u = Q.front();
Q.pop();
if (u.level == -1)
v.level = 0;
if (u.level == n-1)
continue;
v.level = u.level + 1;
v.weight = u.weight + arr[v.level].weight;
v.profit = u.profit + arr[v.level].value;
if (v.weight <= W && v.profit > maxProfit)
maxProfit = v.profit;
v.bound = bound(v, n, W, arr);
if (v.bound > maxProfit)
Q.push(v);
v.weight = u.weight;
v.profit = u.profit;
v.bound = bound(v, n, W, arr);
if (v.bound > maxProfit)
Q.push(v);
}
return maxProfit;
}
int main()
{
int W = 55; // Weight of knapsack
Item arr[] = {{10, 60}, {20, 100}, {30, 120}};
int n = sizeof(arr) / sizeof(arr[0]);
cout << "Maximum possible profit = "
<< knapsack(W, arr, n);
return 0;
}
**SEE IF THIS HELPS**