Sliding Puzzle using BFS - algorithm

I am working on Leetcode problem https://leetcode.com/problems/sliding-puzzle/
class Solution {
public:
int slidingPuzzle(vector<vector<int>>& board) {
int res = 0;
set<vector<vector<int>>> visited;
queue<pair<vector<vector<int>>, vector<int>>> q;
vector<vector<int>> correct{{1, 2, 3}, {4, 5, 0}};
vector<vector<int>> dirs{{0, -1}, {-1, 0}, {0, 1}, {1, 0}};
for (int i = 0; i < 2; ++i) {
for (int j = 0; j < 3; ++j) {
if (board[i][j] == 0) q.push({board, {i, j}});
}
}
while (!q.empty()) {
for (int i = q.size() - 1; i >= 0; --i) {
vector<vector<int>> t = q.front().first;
auto zero = q.front().second; q.pop();
if (t == correct) return res;
visited.insert(t);
for (auto dir : dirs)
{
int x = zero[0] + dir[0], y = zero[1] + dir[1];
if (x < 0 || x >= 2 || y < 0 || y >= 3) continue;
/* option1
vector<vector<int>> cand = t;
swap(cand[zero[0]][zero[1]], cand[x][y]);
if (visited.count(cand)) continue;
q.push({cand, {x, y}});
*/
/* option2
swap(t[zero[0]][zero[1]], t[x][y]);
if (visited.count(t)) continue;
q.push({t, {x, y}});
swap(t[zero[0]][zero[1]], t[x][y]);
*/
}
}
++res;
}
return -1;
}
};
if I keep option1 remove option2 it works,
however when I keep option2 remove option1 it doesn't work!
But these two code block should work the same. I have been trying to figure it out for a couple of hours. So frustrated and no clue

The Bug is in here if (visited.count(t)) continue;
basically, when visited.count(t) is true you will not undo the swap.

The purpose of option1 and option2 is to generate a new valid board state. In your option1, you follow the following states:
copy the current board state into a new temporary board instance (e.g., cand vector)
move the empty tile towards dir
skip the following step if you already visited the new state before
insert the new state into the queue
It works perfectly fine, except the memory utilization. That's why you probably tried doing the moves in-place (e.g., in your option2). The steps of your option2 is like this:
move the empty tile towards dir
skip the following steps if you already visited the new state before <-- this is where you made the mistake
insert the new state into the queue
move back the empty tile to it's original location
You made the mistake in your 2nd step, as you do not undo the change if a newly generated state is already visited. Please check the following code, it will solve your problem:
// option2
swap(t[zero[0]][zero[1]], t[x][y]);
if (!visited.count(t)) q.push({t, {x, y}});
swap(t[zero[0]][zero[1]], t[x][y]);

Related

How to solve the knapsack Problem when more than two properties of the Item are given (3 variables)

In the knapsack Problem how to solve it if one more property other than that of weight and value of the Item is given? Like recently I was asked a question where I was given 3 properties of the same items, Weight, Value and Type:
int weights[5] = {1, 3, 5, 9, 10};
int values[5] = {11, 13, 1, 19, 9};
int types[5] = {1,2,1,3,4};
int capacity = 26;
We can choose items of each type only once, e.g. we can have only one item of type = 1 in our final knapsack, so we either choose the item with weight 1 or the item with weight 5 both cannot be present. We have to maximize the profit we get.
I was thinking along the lines of a 3D matrix, but I'm not able to think of the proper solution, if I couldn't even think of the base case in this situation for the types, how would the recursive solution look like in this case?
Here is what I tried, I choose each element, the type of the element is put in a set, then we recurse. If the next item type is already present in the set, then we remove it and then recalculate the max value for that particular type among all of them, but if the item type is not present in the set, then we have not considered it, and we add it to the set and proceed further.
I also have a lingering doubt about the base case. Since we can have a different item of the same type which gives a more profit, in my base case, if the value for that particular item type is already considered, then it will return the same output without maximizing it for the second item of the same type. But then I countered myself that the n and w values are different for the same type so it will in fact maximize this too. Is this correct?
Related Questions that I found but weren't answered or Did not have a Pseudo code on which I could build upon:
Solving the knapsack problem with special constraint
How can I solve knapsack problems with 3 variables?
After reading the second link, I'm also curious on how we could apply the constraint of the Volume, how would the code actually look like with the base cases?
I was also suggested to use a map of (string, int) values to store the unique values from the recursion, which method would be better? to use a map or to use 3D table?
Here is my code:
set<int> ttypes;
int static t2[6][26][5];
int knapSack_Memo_Modified(int weights[], int values[], int types[], int w, int n){
if(w <= 0 || n <= 0){
return 0;
}
if(t2[n][w][types[n-1]] != -1){
return t2[n][w][types[n-1]];
}
if(ttypes.count(types[n-1])){
ttypes.erase(types[n-1]);
return t2[n][w][types[n-1]] = max(t2[n][w][types[n-1]], knapSack_Memo_Modified(weights, values, types, w, n-1));
}
else{
ttypes.insert(types[n-1]);
if(weights[n-1] <= w){
return t2[n][w][types[n-1]] = max((values[n-1]+knapSack_Memo_Modified(weights, values, types, w-weights[n-1], n-1)), (knapSack_Memo_Modified(weights, values, types, w, n-1)));
}
else if(weights[n-1] > w){
return t2[n][w][types[n-1]] = knapSack_Memo_Modified(weights, values, types, w, n-1);
}
}
}
int main(){
int weights[5] = {1, 3, 5, 9, 10};
int values[5] = {11, 13, 1, 19, 9};
int types[5] = {1,2,1,3,4};
int capacity = 25;
memset(t, -1, sizeof(t));
int ans = knapSack_Memo_Modified(weights, values, types, capacity, 5);
int mx = 0;
for(int i = 0; i < 6; i++){
for(int j = 0; j < 26; j++){
for(int k = 0; k < 5; k++){
mx = max(mx, t2[i][j][k]);
}
}
}
cout << mx << endl;
}

How to Solve Assignment Problem With Constraints?

Assume there are N people and M tasks are there and there is a cost matrix which tells when a task is assigned to a person how much it cost.
Assume we can assign more than one task to a person.
It means we can assign all of the tasks to a person if it leads to minimum cost.
I know this problem can be solved using various techniques. Some of them are below.
Bit Masking
Hungarian Algorithm
Min Cost Max Flow
Brute Force( All permutations M!)
Question: But what if we put a constraint like only consecutive tasks can be assigned to a person. 
    T1   T2  T3
P1  2   2    2
P2  3   1    4
Answer: 6 rather than 5
Explanation:
We might think that , P1->T1, P2->T2, P1->T3 = 2+1+2 =5 can be answer but it is not because (T1 and T3 are consecutive so can not be assigned to P1)
P1->T1, P1->T2, P1-T3 = 2+2+2 = 6
How to approach solving this problem?
You can solve this problem using ILP.
Here is an OPL-like pseudo-code:
**input:
two integers N, M // N persons, M tasks
a cost matrix C[N][M]
**decision variables:
X[N][M][M] // An array with values in {0, 1}
// X[i][j][k] = 1 <=> the person i performs the tasks j to k
**constraints:
// one person can perform at most 1 sequence of consecutive tasks
for all i in {1, N}, sum(j in {1, ..., M}, k in {1, ..., M}) X[i][j][k] <= 1
// each task is performed exactly once
for all t in {1, M}, sum(i in {1, ..., N}, j in {1, ..., t}, k in {t, ..., M}) X[i][j][k] = 1
// impossible tasks sequences are discarded
for all i in {1, ..., N}, for all j in {1, ..., M}, sum(k in {1, ..., j-1}) X[i][j][k] = 0
**objective function:
minimize sum(i, j, k) X[i][j][k] * (sum(t in {j, ..., k}) C[t])
I think that ILP could be the tool of choice here, since more often that not scheduling and production-planning problems are solved using it.
If you do not have experience coding LP programs, don't worry, it is much easier than it looks like, and this problem is rather easy and nice to get started.
There also exists a stackexchange dedicated to this kind of problems and solutions, the OR stack exchange.
This looks np-complete to me. If I am correct, there is not going to be a universally quick solution, and the best one can do is approach this problem using the best possible heuristics.
One approach you did not mention is a constructive approach using A* search. In this case, the search in would move along the matrix from left to right, adding candidate items to a priority queue with every step. Each item in the queue would consist of the current column index, the total cost expended so far, and the list of people who have acted so far. The remaining-cost heuristic for any given state would be the sum of the columnar minima for all remaining columns.
I'm certain that this can find a solution, I'm just not sure it is the best approach. Some quick Googling shows that A* has been applied to several types of scheduling problems though.
Edit: Here is an implementation.
public class OrderedTasks {
private class State {
private final State prev;
private final int position;
private final int costSoFar;
private final int lastActed;
public State(int position, int costSoFar, int lastActed, State prev) {
super();
this.prev = prev;
this.lastActed = lastActed;
this.position = position;
this.costSoFar = costSoFar;
}
public void getNextSteps(int[] task, Consumer<State> consumer) {
Set<Integer> actedSoFar = new HashSet<>();
State prev = this.prev;
if (prev != null) {
for (; prev!=null; prev=prev.prev) {
actedSoFar.add(prev.lastActed);
}
}
for (int person=0; person<task.length; ++person) {
if (actedSoFar.contains(person) && this.lastActed!=person) {
continue;
}
consumer.accept(new State(position+1,task[person]+this.costSoFar,
person, this));
}
}
}
public int minCost(int[][] tasksByPeople) {
int[] cumulativeMinCost = getCumulativeMinCostPerTask(tasksByPeople);
Function<State, Integer> totalCost = state->state.costSoFar+(state.position<cumulativeMinCost.length? cumulativeMinCost[state.position]: 0);
PriorityQueue<State> pq = new PriorityQueue<>((s1,s2)->{
return Integer.compare(totalCost.apply(s1), totalCost.apply(s2));
});
State state = new State(0, 0, -1, null);
for (; state.position<tasksByPeople.length; state = pq.poll()) {
state.getNextSteps(tasksByPeople[state.position], pq::add);
}
return state.costSoFar;
}
private int[] getCumulativeMinCostPerTask(int[][] tasksByPeople) {
int[] result = new int[tasksByPeople.length];
int cumulative = 0;
for (int i=tasksByPeople.length-1; i>=0; --i) {
cumulative += minimum(tasksByPeople[i]);
result[i] = cumulative;
}
return result;
}
private int minimum(int[] arr) {
if (arr.length==0) {
throw new RuntimeException("Not valid for empty arrays.");
}
int min = arr[0];
for (int i=1; i<arr.length; ++i) {
min = Math.min(min, arr[i]);
}
return min;
}
public static void main(String[] args) {
OrderedTasks ot = new OrderedTasks();
System.out.println(ot.minCost(new int[][]{{2, 3},{2,1},{2,4},{2,2}}));
}
}
I think your question is very similar to:
Finding the minimum value
Probably not the best approach if the number of workers is large, but easy to understand and implement could be
get a list all the possible combination with repetition of workers W, for example using the algorithm in https://www.geeksforgeeks.org/combinations-with-repetitions/ . This would give you things like [[W1,W3,W2,W3,W1],[W3,W5,W5,W4,W5]
Discard combinations where workers are not continuous
bool isValid=true;
for (int kk = 0; kk < workerOrder.Length; kk++)
{
int state=0;
for (int mm = 0; mm < workerOrder.Length; mm++)
{
if (workerOrder[mm] == kk && state == 0) { state = 1; } //it has appeard
if (workerOrder[mm] != kk && state == 1 ) { state = 2; } //it is not contious
if (workerOrder[mm] == kk && state == 2) { isValid = false; break; } //it appeard again
}
if (isValid==false){break;}
}
Use the filtered list of lists to check times using the table and keep the minimum one

iterate through a set goes to infinite loop

i used exactly the same code in both of my files.
and one is work properly while the other one (this one) goes to endless loop.
int arr[5] = {3, 1, 3, 5, 6};
int main() {
int T = 1;
set<int> s;
for (int tc = 0; tc < T; tc++) {
s.emplace(0);
for (auto x : arr) {
auto end = s.end();
for (auto it = s.begin(); it != end; it++) {
// here's where goes to infinite loop
// and i couldn't figure out why..
s.emplace(*it+x);
}
}
}
return 0;
}
below one is well working one
using namespace std;
int main() {
int arr[5] = {3,1,3,5,6}, sum=20;
set<int> s;
s.emplace(sum);
for (auto x : arr) {
auto end = s.end();
for (auto it = s.begin(); it != end; it++) {
s.emplace(*it-x);
}
}
return 0;
}
expected results are s = {1, 4, 7, 8, ...}
all the sum of all the subset of arr.
but not working properly.. i don't know why..
The issue is that you're inserting elements into the set while iterating over it (with the ranged-for loop). The ranged-for loop semantics do not involve remembering the state of the range before the loop started; it's just like writing:
for(auto it = std::begin(container); it < std::end(container); it++)
Now, std::set is an ordered container. So when you insert/emplace elements smaller than the one your iterator points at, you won't see them later on in the iteration; but if you insert larger elements, you will see them. So you end up iterating only over elements you've inserted, infinitely.
What you should probably be doing is not emplace new elements into s during the iteration, but rather place them in some other container, then finally dump all of that new containers' contents into the set (e.g. with an std::inserter to the set and an std::copy).
(Also, in general, all of your code seems kind of suspect, i.e. I doubt you really want to do any of this stuff in the first place.)

Check if vector<int> contains duplicate absolute values

Attempting to determine if a vector contains a duplicate. This applies to the absolute value of the elements in the vector. I have tested my implementation with a few cases and have gotten inconsistent results.
bool has_duplicate(vector<int> v) {
vector<int>::iterator it;
for (it = v.begin(); it != v.end(); ++it) {
if (v[*it] < 0)
v[*it *= -1;
if (count(v.begin(), v.end(), v[*it]) > 1)
return true;
}
return false;
}
vector<int> v1 {1, -1}; // true
vector<int> v3 {3, 4, 5, -3}; // true
vector<int> v2 {2, -2}; // false
vector<int> v4 {3, 4, -3}; // false
vector<int> v5 {-1, 1}; // false
Any insight on the erroneous implementation is appreciated
An iterator is like a pointer, not like an index, so you're definitely misusing them in your code. It didn't compile for me. It looks like you're trying to search every element in the vector against every other element, which is inefficient, with a time complexity closer to O(N^2). Since your function only wants to see whether a duplicate exists, you can stop as soon as you find one. By using a set to keep track of what you've found so far, you have a time complexity closer to O(N*log(N)).
bool has_duplicate(vector<int> v)
{
set<int> s;
for (auto i = v.begin(); i != v.end(); ++i) {
int ai = abs(*i);
if (s.count(ai)) return true;
s.insert(ai);
}
return false;
}
bool hasDuplicate(std::vector<int> v)
{
std::transform(v.begin(), v.end(), v.begin(), ::abs);
std::sort(v.begin(), v.end());
return std::adjacent_find(v.begin(), v.end()) != v.end();
}

Approximation Algorithm for non-intersecting paths in a grid

I recently came across this question and thought I could share it here, since I wasn't able to get it.
We are given a 5*5 grid numbered from 1-25, and a set of 5 pairs of points,that are start and end points of a path on the grid.
Now we need to find 5 corresponding paths for the 5 pairs of points, such that no two paths should overlap. Also note that only vertical and horizontal moves are allowed. Also the combined 5 path should cover the entire grid.
For example we are given the pair of points as:
P={1,22},{4,17},{5,18},{9,13},{20,23}
Then the corresponding paths will be
1-6-11-16-21-22
4-3-2-7-12-17
5-10-15-14-19-18
9-8-13
20-25-24-23
What I have thought of so far:
Maybe i can compute all paths from source to destination for all pairs of points and then check if there's no common point in the paths. However this seems to be of higher time complexity.
Can anyone propose a better algorithm? I would be glad if one could explain through a pseudo code.Thanks
This problem is essentially the Hamiltonian path/cycle problem problem (since you can connect the end of one path to the start of another, and consider all the five paths as a part of one big cycle). There are no known efficient algorithms for this, as the problem is NP-complete, so you do essentially need to try all possible paths with backtracking (there are fancier algorithms, but they're not much faster).
Your title asks for an approximation algorithm, but this is not an optimization problem - it's not the case that some solutions are better than others; all correct solutions are equally good, and if it isn't correct, then it's completely wrong - so there is no possibility for approximation.
Edit: The below is a solution to the original problem posted by the OP, which did not include the "all cells must be covered" constraint. I'm leaving it up for those that might face the original problem.
This can be solved with a maximum flow algorithm, such as Edmonds-Karp.
The trick is to model the grid as a graph where there are two nodes per grid cell; one "outgoing" node and one "incoming" node. For each adjacent pair of cells, there are edges from the "outgoing" node in either cell to the "incoming" node in the other cell. Within each cell, there is also an edge from the "incoming" to the "outgoing" node. Each edge has the capacity 1. Create one global source node that has an edge to all the start nodes, and one global sink node to which all end nodes have an edge.
Then, run the flow algorithm; the resulting flow shows the non-intersecting paths.
This works because all flow coming in to a cell must pass through the "internal" edge from the "incoming" to the "ougoing" node, and as such, the flow through each cell is limited to 1 - therefore, no paths will intersect. Also, Edmonds-Karp (and all Floyd-Warshall based flow algorithms) will produce integer flows as long as all capacities are integers.
Here's a program written in Python that walks all potential paths. It uses recursion and backtracking to find the paths, and it marks a grid to see which locations are already being used.
One key optimization is that it marks the start and end points on the grid (10 of the 25 points).
Another optimization is that it generates all moves from each point before starting the "walk" across the grid. For example, from point 1 the moves are to points 2 & 6; from point 7, the moves are to points 2, 6, 8 & 12.
points = [(1,22), (4,17), (5,18), (9,13), (20,23)]
paths = []
# find all moves from each position 0-25
moves = [None] # set position 0 with None
for i in range(1,26):
m = []
if i % 5 != 0: # move right
m.append(i+1)
if i % 5 != 1: # move left
m.append(i-1)
if i > 5: # move up
m.append(i-5)
if i < 21: # move down
m.append(i+5)
moves.append(m)
# Recursive function to walk path 'p' from 'start' to 'end'
def walk(p, start, end):
for m in moves[start]: # try all moves from this point
paths[p].append(m) # keep track of our path
if m == end: # reached the end point for this path?
if p+1 == len(points): # no more paths?
if None not in grid[1:]: # full coverage?
print
for i,path in enumerate(paths):
print "%d." % (i+1), '-'.join(map(str, path))
else:
_start, _end = points[p+1] # now try to walk the next path
walk(p+1, _start, _end)
elif grid[m] is None: # can we walk onto the next grid spot?
grid[m] = p # mark this spot as taken
walk(p, m, end)
grid[m] = None # unmark this spot
paths[p].pop() # backtrack on this path
grid = [None for i in range(26)] # initialize the grid as empty points
for p in range(len(points)):
start, end = points[p]
paths.append([start]) # initialize path with its starting point
grid[start] = grid[end] = p # optimization: pre-set the known points
start, end = points[0]
walk(0, start, end)
Well, I started out thinking about a brute force algorithm, and I left that below, but it turns out it's actually simpler to search for all answers rather than generate all configurations and test for valid answers. Here's the search code, which ended up looking much like #Brent Washburne's. It runs in 53 milliseconds on my laptop.
import java.util.Arrays;
class Puzzle {
final int path[][];
final int grid[] = new int[25];
Puzzle(int[][] path) {
// Make the path endpoints 0-based for Java arrays.
this.path = Arrays.asList(path).stream().map(pair -> {
return new int[] { pair[0] - 1, pair[1] - 1 };
}).toArray(int[][]::new);
}
void print() {
System.out.println();
for (int i = 0; i < grid.length; i += 5)
System.out.println(
Arrays.toString(Arrays.copyOfRange(grid, i, i + 5)));
}
void findPaths(int ip, int i) {
if (grid[i] != -1) return; // backtrack
grid[i] = ip; // mark visited
if(i == path[ip][1]) // path complete
if (ip < path.length - 1) findPaths(ip + 1, path[ip + 1][0]); // find next path
else print(); // solution complete
else { // continue with current path
if (i < 20) findPaths(ip, i + 5);
if (i > 4) findPaths(ip, i - 5);
if (i % 5 < 4) findPaths(ip, i + 1);
if (i % 5 > 0) findPaths(ip, i - 1);
}
grid[i] = -1; // unmark
}
void solve() {
Arrays.fill(grid, -1);
findPaths(0, path[0][0]);
}
public static void main(String[] args) {
new Puzzle(new int[][]{{1, 22}, {4, 17}, {5, 18}, {9, 13}, {20, 23}}).solve();
}
}
Old, bad answer
This problem is doable by brute force if you think about it "backward:" assign all the grid squares to paths and test to see if the assignment is valid. There are 25 grid squares and you need to construct 5 paths, each with 2 endpoints. So you know the paths these 10 points lie on. All that's left is to label the remaining 15 squares with the paths they lie on. There are 5 possibilities for each, so 5^15 in all. That's about 30 billion. All that's left is to build an efficient checker that says whether a given assignment is a set of 5 valid paths. This is simple to do by linear time search. The code below finds your solution in about 2 minutes and takes a bit under 11 minutes to test exhaustively on my MacBook:
import java.util.Arrays;
public class Hacking {
static class Puzzle {
final int path[][];
final int grid[] = new int[25];
Puzzle(int[][] path) { this.path = path; }
void print() {
System.out.println();
for (int i = 0; i < grid.length; i += 5)
System.out.println(
Arrays.toString(Arrays.copyOfRange(grid, i, i + 5)));
}
boolean trace(int p, int i, int goal) {
if (grid[i] != p) return false;
grid[i] = -1; // mark visited
boolean rtn =
i == goal ? !Arrays.asList(grid).contains(p) : nsew(p, i, goal);
grid[i] = p; // unmark
return rtn;
}
boolean nsew(int p, int i, int goal) {
if (i < 20 && trace(p, i + 5, goal)) return true;
if (i > 4 && trace(p, i - 5, goal)) return true;
if (i % 5 < 4 && trace(p, i + 1, goal)) return true;
if (i % 5 > 0 && trace(p, i - 1, goal)) return true;
return false;
}
void test() {
for (int ip = 0; ip < path.length; ip++)
if (!trace(ip, path[ip][0] - 1, path[ip][1] - 1)) return;
print();
}
void enumerate(int i) {
if (i == grid.length) test();
else if (grid[i] != -1) enumerate(i + 1); // already known
else {
for (int ip = 0; ip < 5; ip++) {
grid[i] = ip;
enumerate(i + 1);
}
grid[i] = -1;
}
}
void solve() {
Arrays.fill(grid, -1);
for (int ip = 0; ip < path.length; ip++)
grid[path[ip][0] - 1] = grid[path[ip][1] - 1] = ip;
enumerate(0);
}
}
public static void main(String[] args) {
new Puzzle(new int[][]{{1, 22}, {4, 17}, {5, 18}, {9, 13}, {20, 23}}).solve();
}
}
The starting array:
[ 0, -1, -1, 1, 2]
[-1, -1, -1, 3, -1]
[-1, -1, 3, -1, -1]
[-1, 1, 2, -1, 4]
[-1, 0, 4, -1, -1]
The result:
[ 0, 1, 1, 1, 2]
[ 0, 1, 3, 3, 2]
[ 0, 1, 3, 2, 2]
[ 0, 1, 2, 2, 4]
[ 0, 0, 4, 4, 4]

Resources