minimum cost to reach destination through tunnels - algorithm

Recently I faced a problem in the interview and not able to answer it. Any help will be appreciated.
Given a two dimensional grid (1 <= row <= 10^9 && 1 <= col <= 10^9) and starting and ending coordinates. we can only go to the four adjacent cells and it cost 1 unit. we also have N tunnels (1 <= N <= 200) whose starting and ending coordinates are given and if we go through the tunnel it costs k unit (1 <= k <= 10^9).
Note: It is not necessary to take tunnels but if we take one it costs k unit of energy per tunnel taken.
we have to find the minimum cost to reach the destination from the starting coordinate.
starting coordinate (1 <= sx, sy <= 10^9)
destination coordinate (1 <= fx, fy <= 10^9)

The problem needs to be transposed into a graph with a weight given to each vertex. Once we have done that, we can use the Dijkstra algorithm to find the shortest path.
Solving the problem thus boils down to transposing the problem into a graph with weighted vertices.
We can go from any cell to any other cell without going through a tunnel. The cost is then the manhattan distance. When the coordinate of a cell c1 is (x1,y1) and another cell c2 is (x2,y2), the manhattan distance between c1 and c2 is d=abs(x2-x1)+abs(y2-y1).
The nodes of the graph will correspond to the starting cell, the final cell, and every tunnel exit cells. The number of nodes in the graph is 2 + n where n is the number of tunnels.
There is a vertex between every node. The weight of a vertex to the final node is simply the manhattan distance. The weight of a vertex to a tunnel exit node is the manhattan distance to the tunnel entry cell plus the weight k associated to the tunnel.
This yields a graph that we can now solve using the Dijkstra algorithm to find the shortest path.

As chmike mentioned, the question can first be transformed into a graph. Then Djikstra's algorithm for finding shortest paths can be used. Here's is my code -
#include<bits/stdc++.h>
using namespace std;
#define int long long int
const int N = 402;
int dp[N][N];
pair<int,int> g[N];
int dist[N];
bool vis[N];
int32_t main(){
int k,a,b,c,d,n,p,q,r,s,index,nodes,val;
cin>>k>>a>>b>>c>>d>>n;
index = 2;
nodes = 2*n+1;
for(int i=1;i<=nodes;i++)
dist[i] = INT_MAX;
memset(vis,false,sizeof(vis));
memset(dp,-1,sizeof(dp));
for(int i=0;i<=nodes;i++)
dp[i][i] = 0;
g[0] = {a,b};
g[1] = {c,d};
dp[0][1] = dp[1][0] = abs(a-c)+abs(b-d);
for(int i=0;i<n;i++){
cin>>p>>q>>r>>s;
dp[index][index+1] = k;
dp[index+1][index] = k;
g[index] = {p,q};
g[index+1] = {r,s};
for(int j=0;j<index;j++){
val = abs(p-g[j].first)+abs(q-g[j].second);
dp[j][index] = dp[index][j] = val;
val = abs(r-g[j].first)+abs(s-g[j].second);
dp[j][index+1] = dp[index+1][j] = val;
}
index += 2;
}
for(int i=0;i<=nodes;i++){
int v = -1;
for(int j=0;j<=nodes;j++){
if(!vis[j] && (v == -1 || dist[j] < dist[v]))
v = j;
}
if(dist[v] == INT_MAX)
break;
vis[v] = true;
for(int j=0;j<=nodes;j++)
dist[j] = min(dist[j], dist[v]+dp[v][j]);
}
cout<<dist[1];
return 0;
}

you can use dynamic programming
#include <bits/stdc++.h>
using namespace std;
#define type long long
int main()
{ //k i sost of travelling through tunnel
//sx and sy are starting coordinates
//fx and fy are ending coordinates
//n are number of tunnels
int k, sx, sy, fx ,fy,n;
cin>>k>>sx>>sy>>fx>>fy>>n;
vector<vector<int>> arr(n, vector<int>(4,0));
map<pair<int, int> , pair<int,int>> mp;
//taking inputof tunnel elements and storing it in a map
for(int i=0; i<n; i++)
{
for(int j=0; j<4; j++)
cin>>arr[i][j];
pair<int,int> a,b;
a= pair<int,int> (arr[i][0], arr[i][1]);
b= pair<int, int> (arr[i][2], arr[i][3]);
mp[a] = b;
mp[b] =a;
}//cin the elements
//function
vector<vector<type>> dp (fx+1, vector<type>(fy+1,LONG_LONG_MAX));
dp[fx][fy] =0; //end
for(int i= fx; i>=0; i--)
{
for(int j= fy; j>=0; j--)
{
//go down
if(j+1< fy)
{
dp[i][j] = min(dp[i][j] , dp[i][j+1]+1 );
}
//go right
if(i+1< fx)
{
dp[i][j] = min(dp[i][j] , dp[i+1][j]+1 );
}
//tunnel
if(mp.find(pair<int, int> (i,j))!= mp.end())
{
pair<int, int> temp= mp[pair<int, int> (i,j)];
int a= temp.first, b= temp.second;
if(dp[a][b]!= LONG_LONG_MAX)
{
dp[i][j] = min(dp[i][j] , dp[a][b]+ k );
}
}
}
}//
cout<<dp[sx][sy]<<'\n';
}
here i have used dp
the array dp is 2-d matrix that saves the cost to reach fx, fy.
we start from bottom up approach, at each cell we find the minimum cost to reach the end.
we check the cost to reach by stepping 1 cell downward i.e. from dp[i][j] to dp[i][j+1] .
then we check the right cell by dp[i+1][j]
we see if tunnel is present.

Related

Manhattan tourist

In my algorithms and datastructures class I have been asked to implement the Manhattan tourist problem using dynamic programming.
I have come to a solution using a combination of dynamic programming and recursive calls, but I seem to get "Time limit exceeded" when putting it to the test on CodeJudge. I haven't been able to figure out why my code isn't fast enough. Any takers?
Best regards.
Description of the problem:
Your are helping the tourist guide company "Manhattan Tourists", that are arranging
guided tours of the city. They want to find a walk between two points on the map that is both interesting and short. The map is a square grid graph. The square grid graph has n rows with n nodes in each row. Let node vi,j denote the jth node on row i. For 1≤I<n and for 1≤j≤n node vi,j is connected to vi+1, j. And for 1≤i≤n and for 1 ≤ j < n node vi,j is connected to vi,j+1. The edges have non-negative edge weights that indicate how interesting that street is. See the graph below for an example of a 5 × 5 grid graph.
They want to find a short interesting walk from the upper left corner (s = v1,1) to the lower right corner (t = vn,n). More precisely, they want to find a path with the possible smallest number of edges, and among all paths with this number of edges they want the path with the maximum weight (the weight of a path is the sum of weights on the path).
All shortest paths have 2n − 2 edges and go from s to t by walking either down or right in each step. In the example below two possible shortest paths (of length 8) are indicated. The dashed path has weigth 38 and the dotted path has weight 30.
Let W [i, j] be the maximal weight you can get when walking from s to vi, j walking either down or right in each step. Let D[i, j] be the weight of the edge going down from vi, j and let R[i, j] be the weight of the edge going right from vi,j.
Description on CodeJudge:
Exercise
Before you can solve this exercise, you must first read, understand and (partly) solve the problem Manhattan Tourists described on the weekplan.
Your task here is to implement your solution. Read the input/output specification below and look at the sample test data in order to learn how to read the input and write the output.
Input format
Line 1: The integer n (1<= n <= 1000).
Line 2..n+1: the n rows of R, each consisting of n-1 integers separated by space.
Line n+2..2n: the n-1 rows of D, each consisting of n integers separated by space.
Output format:
Line 1: The maximum interest score of a shortest walk.
Heres my code so far:
public static void main(String[] args) {
Scanner console = new Scanner(System.in);
int n = console.nextInt();
int[][] R = new int[n][n-1];
int[][] D = new int[n-1][n];
for(int i = 0; i < n; i++) {
for(int j = 0; j < n-1; j++) {
R[i][j] = console.nextInt();
}
}
for(int i = 0; i < n-1; i++) {
for(int j = 0; j < n; j++) {
D[i][j] = console.nextInt();
}
}
System.out.println(opt(R, D, n, n-1, n-1));
}
public static int opt(int[][]R, int[][]D, int n, int i, int j) {
int[][] result = new int[n][n];
if(i==0 && j==0) {
if(result[i][j] == 0) {
result[i][j] = 0;
}
return result[i][j];
} else if(i == 0) {
if(result[i][j] == 0) {
result[i][j] = opt(R,D,n,i,j-1) + R[i][j-1];
}
return result[i][j];
}else if(j == 0) {
if(result[i][j] == 0) {
result[i][j] = opt(R,D,n,i-1,j) + D[i-1][j];
}
return result[i][j];
}else if(result[i][j] == 0) {
result[i][j] = max(opt(R, D, n, i, j-1) + R[i][j-1],opt(R, D, n, i-1, j) + D[i-1][j]);
}
return result[i][j];
}
public static int max(int i, int j) {
if(i > j) {
return i;
}
return j;
}
}
Why a recursion?
The topmost row can be traversed horizontally only. So, for each vertex in the first row the total weight is a sum of weights of branches to the left. You can compute all of them in a single loop as a running total across the row.
For each next row the total weight of the first vertex is a weight of the vertex above it plus the weight of the branch between them. And the total weight of each next vertex in the row is the bigger one from two possible when coming from above or from left.
All that can be computed iteratively with two nested loops.

Special case in shortest path algorithm

I have given a graph with V vertices, E edges, a source vertex s and a number m
The weight of each edge is equal to one
I have to find the shortest path to all those nodes whose distance from the source node is lesser than given number m
My approach:- I used Dijkstra algorithm and find a path for all nodes
and then selected those nodes whose distance is less than m but I am getting Time
limit exceed.
Is there any better approach or any algorithm anyone can suggest?
Update:-
I used BFS but still, I am getting TLE on some cases I am trying not to transverse all nodes rather than only those whose distance is less than m from source s and storing them in temp
Please correct me if my approach is wrong.
Here is my code
#include <bits/stdc++.h>
using namespace std;
const long long N = 5*1e4;
const long long W = 1e9;
const long long INF = 1e9;
vector<long long> g[N]; //graph
long long dist[N]; //distance
bool visited[N]; // is node visited or not
void shortest_path(long long s,long long m){
fill(dist, dist + N, INF);
fill(visited, visited + N, 0);
dist[s] = 0;
vector<int>temp;
queue<long long>q; //Queue
q.push(s);
while(!q.empty())
{
long long v = q.front();
q.pop();
if(visited[v]) continue;
visited[v] = 1;
temp.push_back(v); //storing nodes in temp
for(auto it: g[v])
{
long long u = it;
if(dist[v] + 1<= m) // nodes those distance is less than m
{
dist[u] = dist[v] + 1;
q.push(u);
}
}
}
for(int i=0;i<temp.size();i++){
cout<<temp[i]<<" ";
}
}
int main()
{
long long n;
cin>>n;
for(long long i = 0; i < n; ++i) g[i].clear();
for(long long i = 0; i < n-1; i++)
{
long long u,v;
cin>>u>>v;
u--;v--;
g[u].push_back(v);
g[v].push_back(u);
}
long long q;
cin>>q;
for(long long i=0;i<q;i++){
long long s,m;
cin>>s>>m;
s--;
shortest_path(s,m);
cout<<endl;
}
return 0;
}
Dijkstra's is just BFS that works on weighted graphs thanks to a priority queue, but if your graph is unweighted you can just use BFS

Construct any bipartite graph with degree constraints

We need to construct a bipartite graph with N vertices each, on the two parts, and with total number of edges equal to M.
The vertices on the left are numbered from 1 to N.
The vertices on the right are also numbered from 1 to N.
The degree of every vertex to be greater than or equal to X, and to be lesser than or equal to Y. i.e. for all v, X ≤ deg(v) ≤ Y
Given four integers N, M, X, Y we need to construct some bipartite graph satisfying this property. If there does not exist any such graph, then also tell the same.
Example :
If N=2 , M=3 , X=1 and Y=2
then the 3 edges in bipartite graph will be : (1,1),(2,2) and (1,2)
If N=2 , M=3 , X=1 and Y=1 then no bipartite graph exists.
How can this problem be solved if
1 ≤ N ≤ 100
1 ≤ X ≤ Y ≤ N
0 ≤ M ≤ N * N
Original question link
Obviously, the variables need to satisfy:
X * N <= M <= Y * N
Otherwise, there will be no solution.
Finding the edges could be done in waves. Start by connecting each node i from the first set to the according node i from the second set. In the next wave, connect i with (i + 1) mod N. Then i with (i + 2) mod N and so one. This will increase the degree of each vertex by exactly one in each wave. Stop whenever you have constructed M edges. This may also happen during a wave.
ACM ICPC 2016 India Preliminary Round Problem.
Link
The contest is now ended. I couldn't submit the answer (was about to submit the code just 10 secs before the end and my Internet stopped working).
d is equivalent to X in the OP's version of the problem.
D is equivalent to Y in the OP's version of the problem.
t is the number of test cases.
I made the code as per the original question in the link.
The logic is similar to
Nico Schertler's one. My complexity will be a little more because instead of just connecting, i+xth node to i in the xth iteration, I have used a set that finds the first element not connected in the range [1..N] and connects them.
This is my code:
#include <bits/stdc++.h>
using namespace std;
int main() {
int t, n, m, d, D;
cin >> t;
while(t--) {
cin >> n >> m >> d >> D;
if(n*D < m || n*d > m)
printf("-1\n");
else {
vector <set <int> > v(n);
int edges = 0, count = 0;
while(count != d) {
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
if(v[i].find(j) == v[i].end()) {
v[i].insert(j);
++edges;
break;
}
if(edges == m)
break;
}
if(edges == m)
break;
}
++count;
}
while(edges < m) {
for(int i = 0; i < n; i++) {
if(v[i].size() == D)
continue;
for(int j = 0; j < n; j++) {
if(v[i].find(j) == v[i].end()) {
v[i].insert(j);
++edges;
break;
}
if(edges == m)
break;
}
if(edges == m)
break;
}
}
for(int i = 0; i < n; i++) {
set <int>::iterator it = v[i].begin();
for(; it != v[i].end(); ++it) {
printf("%d %d\n", i+1, (*it)+1);
}
}
}
}
return 0;
}
I don't know whether this code is correct or not.

Time Complexity O(V^3) or O(V^2)?

I'm new for analyzing the algorithms and the time for them.. This algorithm is posted in http://geeksforgeeks.com and they wrote that the time complexity of the algorithm is O(V^2) which i think that it's O(V^3):
int minDistance(int dist[], bool sptSet[])
{
// Initialize min value
int min = INT_MAX, min_index;
for (int v = 0; v < V; v++)
if (sptSet[v] == false && dist[v] <= min)
min = dist[v], min_index = v;
return min_index;
}
// A utility function to print the constructed distance array
int printSolution(int dist[], int n)
{
printf("Vertex Distance from Source\n");
for (int i = 0; i < V; i++)
printf("%d \t\t %d\n", i, dist[i]);
}
// Funtion that implements Dijkstra's single source shortest path algorithm
// for a graph represented using adjacency matrix representation
void dijkstra(int graph[V][V], int src)
{
int dist[V]; // The output array. dist[i] will hold the shortest
// distance from src to i
bool sptSet[V]; // sptSet[i] will true if vertex i is included in shortest
// path tree or shortest distance from src to i is finalized
// Initialize all distances as INFINITE and stpSet[] as false
for (int i = 0; i < V; i++)
dist[i] = INT_MAX, sptSet[i] = false;
// Distance of source vertex from itself is always 0
dist[src] = 0;
// Find shortest path for all vertices
for (int count = 0; count < V-1; count++)
{
// Pick the minimum distance vertex from the set of vertices not
// yet processed. u is always equal to src in first iteration.
int u = minDistance(dist, sptSet);
// Mark the picked vertex as processed
sptSet[u] = true;
// Update dist value of the adjacent vertices of the picked vertex.
for (int v = 0; v < V; v++)
// Update dist[v] only if is not in sptSet, there is an edge from
// u to v, and total weight of path from src to v through u is
// smaller than current value of dist[v]
if (!sptSet[v] && graph[u][v] && dist[u] != INT_MAX
&& dist[u]+graph[u][v] < dist[v])
dist[v] = dist[u] + graph[u][v];
}
// print the constructed distance array
printSolution(dist, V);
}
Where the graph represented inside graph[][] (matrix representation).
Thanks in advance
The solution is indeed O(V^2):
for (int i = 0; i < V; i++)
dist[i] = INT_MAX, sptSet[i] = false;
This part runs BEFORE the main loop, and in complexity of O(V) -.
for (int count = 0; count < V-1; count++)
{
This is the main loop, it runs O(V) times overall, and each time it requires:
int u = minDistance(dist, sptSet);
This runs one time per each different value of count, and its complexity is O(V), so we have O(V^2)` by now.
sptSet[u] = true;
This is O(1), and runs O(V) times.
for (int v = 0; v < V; v++)
This loop runs O(V) times, for each value of count, let's examine what happens each time you run it:
if (!sptSet[v] && graph[u][v] && dist[u] != INT_MAX
&& dist[u]+graph[u][v] < dist[v])
dist[v] = dist[u] + graph[u][v];
All of those are O(1), and done per each (count,v) pair, and there are O(V^2) of those pairs.
So, totally O(V^2).
Note that for more efficient graph representation, we can run Dijkstra's algorithm in O(E + VlogV), which might be better in case of sparse graphs.

Backtracking optimization

recently I was trying to solve famous little bishops algorithmic problem. In one of the websites I read that I should divide chessboard into black and white parts to optimize the execution. After that I should use backtracking to count number of possible ways to put bishops on black squares and white squares separetely.
In the following code I try to put 6 bishops ONLY ON WHITE squares of an 8 by 8 chessboard. I do it only to verify that technique is really working.
//inside main function
int k = 6; //number of bishops
int n = 8; //length of one side of chessboard
Integer[] positions = new Integer[k];
long result = backtrack(positions, 0, n);
//find how many times we double counting each possible combination of bishops
int factor = 1;
for(int i = k; i>0; i--) {
factor = factor * i;
}
System.out.println("The result is " + result/factor);
//implementation of other functions
public long backtrack(Integer[] prevPositions, int k, int n) {
if(k == 6) {
return 1;
}
long sum = 0;
Integer[] candidates = new Integer[n*n];
int length = getCandidates(prevPositions, k, candidates, n);
for(int i=0 ; i<length ; i++) {
prevPositions[k] = candidates[i];
sum += backtrack(prevPositions,k+1,n);
}
return sum;
}
public Integer getCandidates(Integer[] prevPositions, int k, Integer[] candidates, int n) {
int length = 0;
//only white squares are considered as candidates, hence i+=2
for (int i = 0; i < n*n; i+=2) {
boolean isGood = true;
int iRow = i / n;
int iCol = i % n;
for (int j = 0; j < k; j++) {
int prev = prevPositions[j];
if (i == prev) {
isGood = false;
break;
} else {
int prevRow = prev / n;
int prevCol = prev % n;
if (Math.abs(iRow - prevRow) == Math.abs(iCol - prevCol)) {
isGood = false;
break;
}
}
}
if(isGood) {
candidates[length] = new Integer(i);
length++;
}
}
return length;
}
Even though I can see why dividing chessboard into white and black squares optimizes the problem, it is still takes around 11 seconds to count number of possible ways to put all bishops ONLY ON WHITE SQUARES. Can you help me pls? What am I doing wrong?
here are a few ways to improve your search.
(1) Instead of generate-and-test, you could consider finite domain search, where every bishop has a "domain" of possible places. Whenever you place a bishop, you prune the domains of the remaining bishops. If a bishop's domain becomes empty, you must backtrack.
(2) As a refinement, if you have n bishops to place and m < n places left, you must backtrack.
(3) Use dynamic programming/memoization, where you store solutions for 1 bishop, 2 bishops, ..., and compute the set of n + 1 bishop solutions from the set of n bishop solutions.
(4) Exploit symmetry to reduce your search space. In this case there is (at least) black/white symmetry and rotational/reflective symmetry.
(5) Try to find a better representation. For example, bit patterns.
(6) If you use a different representation, look into using a "trail" (cf. Prolog) to track the operations you need to undo on backtracking.
Cheers!

Resources