Longest straight in a matrix - algorithm

I came across a programming challenge that has been tearing me up for those. It's named "dice straight".
Basically, you're given m x 6 matrices (the column length is always 6 but the rows vary), and you're to find the length of the longest string of adjacent integers that can be formed picking one integer from each row. That means, you can't take 2 integers from one row and you can't leave a row out.
For example, one of the matrix is
[4 8 15 16 23 42]
[8 6 7 5 30 9 ]
[1 2 3 4 55 6 ]
[2 10 18 36 54 86]
The longest straight can be formed taking 2 from row4, 3 from row3, 4 from row1 and 5 from row 2. That's 2,3,4,5. So it returns 4, the length.
The code I have now works for the above matrix and moderately sized matrices, but when it gets to 100 x 6 matrices, it runs forever. I'm using a combination of back track algorithm and depth first. First, I combine the rows into one array and sort them, then, using a stack, I pick numbers on the condition that it's adjacent to the stack top and it's not on the same row as any integer in the stack, and when it reaches a dead-end, I dequeue until I get to last working solution.
static int maxLength(Face[] faces, int d){
faces = quickSort(faces, 0, faces.length - 1);
for (int i = 0; i < faces.length - 1; i++) {
if(faces[i].side == faces[i+1].side && faces[i].dice > faces[i+1].dice){
Face temp = faces[i];
faces[i] = faces[i+1];
faces[i+1] = temp;
}
}
//System.out.println(faces.length);
for (int i = 0; i < faces.length; i++) {
//System.out.print(faces[i]+" ");
}
int maxLength = 1;
for (int i = 0; i < faces.length; i++) {
Stack<Face> tree = new Stack<>();
Stack<Integer> dices = new Stack<>();
Stack<Integer> sides = new Stack<>();
int length = 1;
tree.add(faces[i]);
dices.add(faces[i].dice);
sides.add(faces[i].side);
int pos = i;
//System.out.print(faces[pos].side + ", ");
while(!tree.isEmpty() && pos < faces.length - 1){
pos++;
//System.out.println(faces[pos] + "}"+faces[pos + 1]);
if(faces[pos].side - faces[pos - 1].side == 2){
for(Face ig : tree){
//System.out.print(ig+" ");
}
//System.out.println("/"+faces[pos]+"/"+length);
i = pos;
break;
}
faces[pos].visited = true;
//System.out.print(tree.peek().side + " ");
if(!dices.contains(faces[pos].dice) && faces[pos].side - tree.peek().side == 1){
tree.push(faces[pos]);
dices.push(faces[pos].dice);
//System.out.print(faces[pos].side + " ");
length++;
maxLength = Math.max(length, maxLength);
if(maxLength == d){
i = 5000000;
//System.out.println("beeeeeee");
//System.out.println(tree.size());
for(Face ig : tree){
//System.out.print(ig+" ");
}
break;
}
}else if(faces[pos].side - tree.peek().side == 2){
Face a = tree.peek();
Face x = tree.pop();
//System.out.println(tree.peek()+"|"+x+"|"+length+"|"+faces[pos]);
pos = Arrays.asList(faces).indexOf(x)+1;
dices.pop();
length--;
for(Face ig : tree){
//System.out.println(ig);
}
//System.out.println();
}else if(faces[pos].side - tree.peek().side > 2){
}
}
//System.out.println();
for(Face ig : tree){
//System.out.println(ig);
}
}
return maxLength;
}
"Face" is a class with 2 fields. 'Side', which represents the integer in a row i and dice, which represents 'i'. Face[] is an array of all the elements in the matrix, sorted in ascending order of 'side'. So Face[] for the above matrix would be
1(2) 2(2) 2(3) 3(2) 4(0) 4(2) 5(1) 6(1) 6(2) 7(1) 8(0) 8(1) 9(1) 10(3) 15(0) 16(0) 18(3) 23(0) 30(1) 36(3) 42(0) 54(3) 55(2) 86(3) in x(y) format where x is side and y is dice.
I found the challenge in the link below. If you don't understand my question, please check this.
https://code.google.com/codejam/contest/6314486/dashboard#s=p0&a=0
I'll very much appreciate it if anyone points me in the right direction. Thank you.

Related

Converging maze: Largest cycle

This question was asked in one interview and i am still hunting for the best solution.
You are given a maze with N cells. Each cell may have multiple entry points but not more than one exit
(ie. entry/exit points are unidirectional doors like valves).
The cells are named with an integer value from 0
to N-1.
You need to find the the length of the largest cycle in the maze. Return -1 if there are no cycles.
INPUT FORMAT
First line has the number of cells N
Second line has list of N values of the edge[] array. edge[i] contains the cell number that
can be reached from of cell ‘i’ in one step. edge[i] is -1 if the ‘i’th cell doesn’t have an exit.
OUTPUT FORMAT
length of the largest cycle.
Sample input:
23
4 4 1 4 13 8 8 8 0 8 14 9 15 11 -1 10 15 22 22 22 22 22 21
Sample output
6
I have already tried to do this with DFS to find all possible cycles and print the largest cycle size.
Please let me know if there is any better solution for the same.
Given a node in the graph, there's a unique maximal path starting from it (since there's at most one exit from any node). It may or may not cycle.
It's easy to find the eventual cycle length starting from a node: keep following exit nodes, recording nodes in a set along the path. Stop when you either find no exit node, or you're about to visit a previously visited node. If there's no exit node there's no cycle, and otherwise you can find the cycle length by starting at the previously visited node, and re-trace the cycle. [You could also use Floyd's algorithm here which would require O(1) rather than O(N) storage, but we're going to use O(N) storage anyway in the next step].
Using this, one can find the maximum cycle in O(N) time: repeat the above algorithm for each node in the graph, but cache results (storing -1 if there's no cycle found). You have to be careful to stop the cycle-finding above if you find a previously cached result along your path, and once you've found a result for a node, you must cache the result for all nodes along the path until you find a node who's result is already cached. The size of the largest cycle is the value of the largest cached value.
This is O(N) runtime: each edge (of which there's at most N) is followed at most 3 times in the graph, and the cache is updated exactly once for each node in the graph. It's uses O(N) additional storage.
public static int solution(int arr[])
{
ArrayList<Integer> sum = new ArrayList<>();
for(int i = 0; i < arr.length; i ++)
{
ArrayList<Integer> path = new ArrayList<>();
int j = i;
int tempSum = 0;
while(arr[j]<arr.length && arr[j]!=i && arr[j]!=-1 && !path.contains(j))
{
path.add(j);
tempSum+=j;
j=arr[j];
if(arr[j]==i)
{
tempSum+=j;
break;
}
}
if(j<arr.length && i == arr[j])
sum.add(tempSum);
}
if(sum.isEmpty())
return -1;
return Collections.max(sum);
}
Here is an implementation in JavaScript. I didn't use any fancy features of JavaScript, so the algorithm can be readily seen from the code. On the other hand, it does need ES6 support to run (forget IE):
function largestCycle(edges) {
var result, visitedFrom, startCell, cell, cells;
result = [];
visitedFrom = Array(edges.length).fill(-1);
for (startCell = 0; startCell < edges.length; startCell++) {
cells = [];
for (cell=startCell; cell>-1 && visitedFrom[cell]===-1; cell = edges[cell]) {
visitedFrom[cell] = startCell;
cells.push(cell);
}
if (cell > -1 && visitedFrom[cell] === startCell) {
cells = cells.slice(cells.indexOf(cell));
if (cells.length > result.length) result = cells;
}
}
return result;
}
// Snippet I/O
var input = document.querySelector('textarea');
var output = document.querySelector('span');
(input.oninput = function () {
// Get input as array of numbers
var edges = input.value.trim().split(/\s+/).map(Number);
// Apply algorithm
var cycle = largestCycle(edges);
// Output result
output.textContent = cycle.length + ': ' + JSON.stringify(cycle);
})(); // Execute also at page load
Input:<br>
<textarea style="width:100%">4 4 1 4 13 8 8 8 0 8 14 9 15 11 -1 10 15 22 22 22 22 22 21</textarea><br>
Greatest Cycle: <span></span>
This runs in O(n). Even though the outer loop has both a nested loop and an expression that iterates over an array (using slice and indexOf), these sub-iterations are only executed once per cell, so in total this is still O(n).
The function does not only return the cycle size, but also the array containing the list of cells that belong to that cycle. It is a small overhead, but allows to better verify the result.
Python implementation of the solution suggested by trincot.
Explanation:
iterate over each node
For each node use the indices to navigate to the next node. Eg(1st iteration : outer for loop)
from 0th index we can reach 4 , from 4th index we can reach 13 , and from 13th index we can reach 11, and so on till we reach the visited node again in our case 0,
viola , we have found the first cycle.
check if visitedFrom[cell] == startCell i.e. 0 add it to the result array.
repeat for next node (step1)
Code
def largestCycle(edges):
result = []
visitedFrom = [-1] * len(edges)
for startCell in range(0, len(edges)):
cells = []
cell = startCell
while cell > -1 and visitedFrom[cell] == -1:
visitedFrom[cell] = startCell
cells.append(cell)
cell = edges[cell]
if cell > -1 and visitedFrom[cell] == startCell:
cells_idx = cells.index(cell)
cells = cells[cells_idx:]
if len(cells) > len(result):
result = cells
return result,len(result)
size = 23
edges = [4, 4, 1, 4, 13, 8, 8, 8, 0, 8, 14, 9, 15, 11, -1, 10, 15, 22, 22, 22, 22, 22, 21]
largestCycle(edges)
Using Prims algorithm to Find max Cycle in the Node
n = int(input())
v = n
e = v+1
arr = [int(i) for i in input().split()]
graph = [[0 for _ in range(n)] for _ in range(n)]
for i in range(0, len(arr)):
graph[i][arr[i]] = 1
for i in graph:
print(i)
def min_ind(wieight, visied):
min_ = -1
ind = -1
for i in range(v):
if(wieight[i] > min_ and visied[i] == False):
min_ = wieight[i]
ind = i
return ind
def printPath(parent, i):
res = []
while(parent[i] != -1):
res.append(i)
i = parent[i]
res.append(i)
return res[::-1]
# Dijkstra
visited = [False for _ in range(v)]
wieight = [0 for _ in range(v)]
parent = [-1 for i in range(v)]
wieight[0] = 0
path = []
for _ in range(v):
u = min_ind(wieight, visited)
if(u == -1):
continue
visited[u] = True
for i in range(v):
if(graph[u][i] > 0 and visited[i] == False):
if(wieight[i] < graph[u][i]):
wieight[i] = graph[u][i]
parent[i] = u
maximum = 0
for i in range(0, len(wieight)):
print("No:", i, " Weight:", wieight[i], " Path:", end=" ")
path = (printPath(parent, i))
maximum = max(maximum, len(path))
print(path, end=" ")
print()
print("Longest Cycle: ", maximum)
here is the solution for the problem but input format is not actually the same.
Here is the input format:
test cases: N
size of array: M
array elements: 1<=a(i)<=M-1 where 0<=i<=M-1
index to which last index points: C
In this problem, we have to count the cells in the largest cycle, here is the code:
class countLargestCycleMaze {
static vertex[] cells;
static class vertex {
int name;
neighbor list;
public vertex(int v, neighbor nb) {
this.name = v;
this.list = nb;
}
}
static class neighbor {
int vnum;
neighbor next;
public neighbor(int v, neighbor nb) {
this.vnum = v;
this.next = nb;
}
}
static int dfs(int v, int m) {
neighbor tmp = cells[v].list;
int c = 0;
while (tmp.vnum != m)
tmp = cells[tmp.vnum].list;
tmp = cells[tmp.vnum].list;
while (tmp.vnum != m) {
tmp = cells[tmp.vnum].list;
c++;
}
return c;
}
public static void main(String[] args) throws java.lang.Exception {
try {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int i, j, n, m, c;
n = Integer.parseInt(br.readLine());
while (n-- > 0) {
m = Integer.parseInt(br.readLine());
StringTokenizer st = new StringTokenizer(br.readLine());
c = Integer.parseInt(br.readLine());
if (c == 0) {
System.out.println("0");
continue;
}
cells = new vertex[m + 1];
for (i = 0; i < m; i++) {
int num = Integer.parseInt(st.nextToken());
cells[i] = new vertex(num, null);
cells[i].list = new neighbor(num, cells[i].list);
}
cells[m] = new vertex(c, null);
cells[m].list = new neighbor(c, cells[m].list);
System.out.println(dfs(0, c));
}
} catch (Exception e) {}
}
}
public class LargestCycleInGraph {
public static int checkCycle(int []cell , int size , int start) {
Set<Integer> set = new HashSet<>();
set.add(start);
for(int i = start ;i< size;i++) {
if( !set.contains(cell[i]) && cell[i] != -1) {
set.add( cell[i] );
}
else return set.size() + 1; // 1 for again come to cycle node
}
return -1;
}
public static int findLargestCycle(int []cell , int size) {
int max = -1;
for(int i =0;i<size;i++) {
//if you want to find sum of largest cycle return "Set" rather than its size and check for max sum
int cyc = checkCycle(cell , size , i);
if(max < cyc)
max = cyc;
}
return max;
}
public static void main(String[] args) {
int size = 23;
int []cell = {4, 4, 1, 4, 13, 8, 8, 8, 0, 8, 14, 9, 15, 11, -1, 10, 15, 22, 22, 22, 22, 22, 21};
int largestCycle = findLargestCycle(cell , size);
System.out.println("Largest cycle Length " +largestCycle);
}
}
def main():
size = int(input())
cell = input().split()
for i in range(0, len(cell)):
cell[i] = int(cell[i])
m = -1
for i in range(0, 23):
if m < check_cycle(cell, i):
m = check_cycle(cell, i)
print("Largest cycle is made of", m, "nodes")
def check_cycle(cell, start):
i = start
if i in cell:
cycle = [i]
j = i
while 1:
for k in cycle:
if cycle.count(k) >= 2:
if cycle[0] == cycle[-1]:
return len(cycle)-1
else:
return 0
else:
cycle.append(cell[j])
j = cell[j]
else:
return 0
main()
Here is my attempt, to traverse each node of the graph:-
#include <stdio.h>
int findingLargestCycle(int noOfInputs, int *edges){
int largestCycle = 0;
for(int i=0; i<noOfInputs; i++){
int currentEdge = edges[i];
int count = currentEdge;
int nextEdge = edges[currentEdge];
int n = 0;
while(currentEdge != nextEdge && n<noOfInputs+1){
if(nextEdge == -1 || currentEdge == -1){
count = 0;
break;
}
if(nextEdge != currentEdge){
count += nextEdge;
}
nextEdge = edges[nextEdge];
n++;
}
if(count > largestCycle && n != noOfInputs+1){
largestCycle = count;
}
}
return largestCycle;
}
int main(){
int testCases;
scanf("%d", &testCases);
int numberOfInputs;
scanf("%d", &numberOfInputs);
int edges[numberOfInputs];
for(int i=0; i<numberOfInputs; i++){
scanf("%d", &edges[i]);
}
printf("%d", findingLargestCycle(numberOfInputs, &edges[0]));
}
O(n) time complexity solution each node is visited only after checking it's visited before or not, so each node is visited only once.
O(n) space complexity ([n]:stack space max + [2*n]:two map used max size)
To observe: there is always a unique path between two nodes(check with any test case), because of condition, only one exit from each node.
C++ code:
#include <iostream>
#include <vector>
#include <unordered_map>
using namespace std;
//res stores result
int res = 0;
//visit to check in before visiting the node, to stop repeat visiting
unordered_map<int,bool> visit;
void dfs(vector<int> & a, unordered_map<int,int> &mp, int i, int k){
if(visit.find(i) != visit.end())
return;
if(a[i] == -1){
visit[i] = true;
return;
}
if(mp.find(i) != mp.end()){
res = max(res, k-mp[i]);
visit[i] = true;
return;
}
mp[i] = k;
dfs(a, mp, a[i], k+1);
visit[i] = true;
}
int main() {
int n;
cin>>n;
vector<int> a(n,0);
for(int i=0;i<n;i++)
cin>>a[i];
for(int i=0;i<n;i++){
if(visit.find(i) == visit.end()){
unordered_map<int,int> mp;
dfs(a, mp, i, 0);
}
}
cout<<res<<endl;
return 0;
}
Solution in C++
#include <bits/stdc++.h>
using namespace std;
bool isCycle(vector<int> arr, int curr, vector<bool> &visited, vector<int> &path)
{
if (curr == -1)
{
return false;
}
if (visited[curr])
{
return true;
}
visited[curr] = true;
path.emplace_back(curr);
if (isCycle(arr, arr[curr], visited, path))
return true;
return false;
}
int largestSumCycle(vector<int> arr)
{
int n = arr.size();
int sum = INT_MIN;
vector<bool> visited(n, false);
for (int i = 0; i < n; i++)
{
visited[i] = true;
vector<int> path;
if (isCycle(arr, arr[i], visited, path))
sum = max(sum, accumulate(path.begin(), path.end(), 0));
visited[i] = false;
}
if (sum == INT_MIN)
return -1;
return sum;
}
This is a common question in interviews, in the same interview they asked this question also for the same details in question.
Q: find the NEAREST MEETING CELL (NMC)
INPUT : same as above + third line has 2 numbers whose nearest meeting cell is to be found.
SAMPLE INPUT
23
4 4 1 4 13 8 8 8 0 8 14 9 15 11 -1 10 15 22 22 22 22 22 21
9 2 (need to find out meeting point of 9 , 2 in the mesh/graph)
OUTPUT
4
CODE:
def main():
testCASES=int(input())
# testCASES=1
for case_number in range(testCASES):
meshsize=input()
mesh=input()
# mesh='4 4 1 4 13 8 8 8 0 8 14 9 15 11 -1 10 15 22 22 22 22 22 21'
det=input()
# det='9 2'
mesh=[int(x) for x in mesh.split()]
det=[int(x) for x in det.split()]
n1=det[0]
n2=det[1]
n1path=[]
n2path=[]
for i in range(len(mesh)):
if not n1path:
n1path.append(mesh[n1])
else:
n1path.append(mesh[n1path[i-1]])
if not n2path:
n2path.append(mesh[n2])
else:
n2path.append(mesh[n2path[i-1]])
nearestList=[]
try:
for x in n1path:
nearestList.append(n2path.index(x))
NEAREST_NODE=n2path[min(nearestList)]
except Exception as e:
NEAREST_NODE = -1
# print(n1path,n2path)
print(NEAREST_NODE)
main()
WORKING:
walks paths from given 2 points, and calculate first common point of n1path and n2path, by using min() function on indices of nearest list. naming is arbitary, but thats the core algo.
it can handle if cycles are present, and still return the first intersection point.
returns -1 if no matches are found.
This is one more variant of the problem, apart from the normal inpt, we're given two nodes, src and dest, and we have to output the node which is the closest to both src and dest.
Here's my solution to finding nearest cell from both src and dest
#include<bits/stdc++.h>
using namespace std;
//returns answer
int solution(vector<int> arr, int src, int dest){
// Two maps, visA for distance from src and visB for distance from dest
// They serve two purpose, if visA[x] == 0, that means we haven't reached that node yet,
// and if it holds any value, say d, that means it is d distance away from the particular node
map<int,int> visA,visB;
int start = arr[src];
int curr = 1;
set<int> s; // contains unique set of nodes to check at last
// iniitializing final nodes
for(auto &x: arr){
s.insert(x);
}
// traversing until we get to a cell where we've already reached
while(visA[start] == 0){
visA[start] = curr; // Marcking the distance
curr++;
start = arr[start];
if(start == -1){
break; // Getting out if we get to a node who is not pointing at any other node
}
}
start = arr[dest];
// Same logic as above but traversing from dest
while(visB[start] == 0){
visB[start] = curr;
curr++;
start = arr[start];
if(start == -1){
break;
}
}
// This is an array of two values, vp[i].first holds the sum of distance of vp[i].second from src and dest.
vector<pair<int,int>> vp;
for(auto &x: s){
if(visA[x] != 0 && visB[x] != 0){ // Checking if we ever got to that particular node from both src and dest or not
pair<int,int> p = {visA[x] + visB[x], x};
vp.push_back(p);
}
}
// sorting and finding the node with list sum of visA[} + visB[]
sort(vp.begin(), vp.end());
return vp[0].second;
}
int main(){
int n; cin>>n;
vector<int> v;
for(int i = 0; i<n; i++){
int a; cin>>a;
v.push_back(a);
}
int a,b; cin>>a>>b;
cout << (solution(v,a,b));
}
function largestCycle(edges) {
var result, visitedFrom, startCell, cell, cells;
result = [];
visitedFrom = Array(edges.length).fill(-1);
for (startCell = 0; startCell < edges.length; startCell++) {
cells = [];
for (cell=startCell; cell>-1 && visitedFrom[cell]===-1; cell = edges[cell]) {
visitedFrom[cell] = startCell;
cells.push(cell);
}
if (cell > -1 && visitedFrom[cell] === startCell) {
cells = cells.slice(cells.indexOf(cell));
if (cells.length > result.length) result = cells;
}
}
return result;
}
// Snippet I/O
var input = document.querySelector('textarea');
var output = document.querySelector('span');
(input.oninput = function () {
// Get input as array of numbers
var edges = input.value.trim().split(/\s+/).map(Number);
// Apply algorithm
var cycle = largestCycle(edges);
// Output result
output.textContent = cycle.length + ': ' + JSON.stringify(cycle);
})(); // Execute also at page load
Input:<br>
<textarea style="width:100%">4 4 1 4 13 8 8 8 0 8 14 9 15 11 -1 10 15 22 22 22 22 22 21</textarea><br>
Greatest Cycle: <span></span>

Find max points in grid such that a particular point is always covered

Question
Jeff loves playing games, Gluttonous snake( an old game in NOKIA era ) is one of his favourites.
However, after playing gluttonous snake so many times, he finally got bored with the original rules.
In order to bring new challenge to this old game, Jeff introduced new rules :
The ground is a grid, with n rows and m columns(1 <= n, m <= 500).
Each cell contains a value v (-1 vi 99999), if v is -1, then this cell is blocked, ≤ ≤ and the snake
can not go through, otherwise, after the snake visited this cell, you can get v point.
The snake can start from any cell along the left border of this ground and travel until it finally
stops at one cell in the right border.
During this trip, the snake can only go up/down/right, and can visit each cell only once.
Special cases :
a. Even in the left border and right border, the snake can go up and down.
b. When the snake is at the top cell of one column, it can still go up, which demands the player to pay all current points , then the snake will be teleported to the bottom cell of this column and vice versa.
After creating such a new game, Jeff is confused how to get the highest score. Please help him to write a program to solve this problem.
Input
The first line contains two integers n (rows) and m (columns), (1 <= n, m <= 500), separated by a single space.
Next n lines describe the grid. Each line contains m integers vi (-1 ≤ vi ≤ 99999)
vi = -1 means the cell is blocked.
Output
Output the highest score you can get. If the snake can not reach the right side, output -1.
Limits
• Memory limit per test : 256 megabytes
• Time limit per test : The faster the better Compile
4 4
-1 4 5 1
2 -1 2 4
3 3 -1 3
4 2 1 2
I have solved the question with code given below then the interviewer changes the question and asked that now the snake always has to take a particular point in its route that is path including that particular point are only valid like if point is (2,1) then it has to take 3 in its path always. and than we have to find the max sum ? i was not able to do it in the interview please please any one help it , just provide link only where this type of problem is done. I applied dfs interviewer told dfs is wrong in this question , i am not able to figure it out why it is wrong and what can be better algorithm to find the answer
Code
import java.util.Scanner;
public class worksApplication {
private static int rows;
private static int col;
private static int[][] a;
private static boolean[][] check;
private static int max1;
private static int max;
public static void main(String args[]) {
Scanner sc = new Scanner(System.in);
rows = sc.nextInt();
col = sc.nextInt();
a = new int[rows][col + 1];
check = new boolean[rows][col];
for (int i = 0; i < rows; i++) {
for (int j = 0; j < col + 1; j++) {
if (j == col) {
a[i][j] = -1;
} else
a[i][j] = sc.nextInt();
}
}
for (int i = 0; i < rows; i++) {
if (a[i][0] != -1) {
check[i][0] = true;
solve(i, 0, a[i][0]);
check[i][0] = false;
max1 = Math.max(max, max1);
}
}
System.out.println(max1);
}
private static void solve(int i, int j, int sum) {
// TODO Auto-generated method stub
if (i - 1 == -1 && check[rows - 1][j] == false && a[rows - 1][j] != -1) {
check[rows - 1][j] = true;
solve(rows - 1, j, a[rows - 1][j]);
check[rows - 1][j] = false;
}
if (i - 1 >= 0 && check[i - 1][j] == false && a[i - 1][j] != -1) {
check[i - 1][j] = true;
solve(i - 1, j, sum + a[i - 1][j]);
check[i - 1][j] = false;
}
if (a[i][j + 1] != -1 && check[i][j + 1] == false) {
check[i][j + 1] = true;
solve(i, j + 1, sum + a[i][j + 1]);
check[i][j + 1] = false;
}
if (i + 1 == rows && a[0][j] != -1 && check[0][j] == false) {
check[0][j] = true;
solve(0, j, a[0][j]);
check[0][j] = false;
}
if (i + 1 < rows && a[i + 1][j] != -1 && check[i + 1][j] == false) {
check[i + 1][j] = true;
solve(i + 1, j, sum + a[i + 1][j]);
check[i + 1][j] = false;
}
if (max < sum) {
max = sum;
}
}
}

How will I solve this using DP?

Question link: http://codeforces.com/contest/2/problem/B
There is a square matrix n × n, consisting of non-negative integer numbers. You should find such a way on it that
starts in the upper left cell of the matrix;
each following cell is to the right or down from the current cell;
the way ends in the bottom right cell.
Moreover, if we multiply together all the numbers along the way, the result should be the least "round". In other words, it should end in the least possible number of zeros.
Input
The first line contains an integer number n (2 ≤ n ≤ 1000), n is the size of the matrix. Then follow n lines containing the matrix elements (non-negative integer numbers not exceeding 10^9).
Output
In the first line print the least number of trailing zeros. In the second line print the correspondent way itself.
I thought of the following: In the end, whatever the answer will be, it should contain minimum powers of 2's and 5's. Therefore, what I did was, for each entry in the input matrix, I calculated the powers of 2's and 5's and stored them in separate matrices.
for (i = 0; i < n; i++)
{
for ( j = 0; j < n; j++)
{
cin>>foo;
matrix[i][j] = foo;
int n1 = calctwo(foo); // calculates the number of 2's in factorisation of that number
int n2 = calcfive(foo); // calculates number of 5's
two[i][j] = n1;
five[i][j] = n2;
}
}
After that, I did this:
for (i = 0; i < n; i++)
{
for ( j = 0; j < n; j++ )
{
dp[i][j] = min(two[i][j],five[i][j]); // Here, dp[i][j] will store minimum number of 2's and 5's.
}
}
But the above doesn't really a valid answer, I don't know why? Have I implemented the correct approach? Or, is this the correct way of solving this question?
Edit: Here are my functions of calculating the number of two's and number of five's in a number.
int calctwo (int foo)
{
int counter = 0;
while (foo%2 == 0)
{
if (foo%2 == 0)
{
counter++;
foo = foo/2;
}
else
break;
}
return counter;
}
int calcfive (int foo)
{
int counter = 0;
while (foo%5 == 0)
{
if (foo%5 == 0)
{
counter++;
foo = foo/5;
}
else
break;
}
return counter;
}
Edit2: I/O Example as given in the link:
Input:
3
1 2 3
4 5 6
7 8 9
Output:
0
DDRR
Since you are interested only in the number of trailing zeroes you need only to consider the powers of 2, 5 which you could keep in two separate nxn arrays. So for the array
1 2 3
4 5 6
7 8 9
you just keep the arrays
the powers of 2 the powers of 5
0 1 0 0 0 0
2 0 1 0 1 0
0 3 0 0 0 0
The insight for the problem is the following. Notice that if you find a path which minimizes the sum of the powers of 2 and a path which minimizes the number sum of the powers of 5 then the answer is the one with lower value of those two paths. So you reduce your problem to the two times application of the following classical dp problem: find a path, starting from the top-left corner and ending at the bottom-right, such that the sum of its elements is minimum. Again, following the example, we have:
minimal path for the
powers of 2 value
* * - 2
- * *
- - *
minimal path for the
powers of 5 value
* - - 0
* - -
* * *
so your answer is
* - -
* - -
* * *
with value 0
Note 1
It might seem that taking the minimum of the both optimal paths gives only an upper bound so a question that may rise is: is this bound actually achieved? The answer is yes. For convenience, let the number of 2's along the 2's optimal path is a and the number of 5's along the 5's optimal path is b. Without loss of generality assume that the minimum of the both optimal paths is the one for the power of 2's (that is a < b). Let the number of 5's along the minimal path is c. Now the question is: are there as much as 5's as there are 2's along this path (i.e. is c >= a?). Assume that the answer is no. That means that there are less 5's than 2's along the minimal path (that is c < a). Since the optimal value of 5's paths is b we have that every 5's path has at least b 5's in it. This should also be true for the minimal path. That means that c > b. We have that c < a so a > b but the initial assumption was that a < b. Contradiction.
Note 2
You might also want consider the case in which there is an element 0 in your matrix. I'd assume that number of trailing zeroes when the product is 1. In this case, if the algorithm has produced a result with a value more than 1 you should output 1 and print a path that goes through the element 0.
Here is the code. I've used pair<int,int> to store factor of 2 and 5 in the matrix.
#include<vector>
#include<iostream>
using namespace std;
#define pii pair<int,int>
#define F first
#define S second
#define MP make_pair
int calc2(int a){
int c=0;
while(a%2==0){
c++;
a/=2;
}
return c;
}
int calc5(int a){
int c=0;
while(a%5==0){
c++;
a/=5;
}
return c;
}
int mini(int a,int b){
return a<b?a:b;
}
pii min(pii a, pii b){
if(mini(a.F,a.S) < mini(b.F,b.S))
return a;
return b;
}
int main(){
int n;
cin>>n;
vector<vector<pii > > v;
vector<vector<int> > path;
int i,j;
for(i=0;i<n;i++){
vector<pii > x;
vector<int> q(n,0);
for(j=0;j<n;j++){
int y;cin>>y;
x.push_back(MP(calc2(y),calc5(y))); //I store factors of 2,5 in the vector to calculate
}
x.push_back(MP(100000,100000)); //padding each row to n+1 elements (to handle overflow in code)
v.push_back(x);
path.push_back(q); //initialize path matrix to 0
}
vector<pii > x(n+1,MP(100000,100000));
v.push_back(x); //pad 1 more row to handle index overflow
for(i=n-1;i>=0;i--){
for(j=n-1;j>=0;j--){ //move from destination to source grid
if(i==n-1 && j==n-1)
continue;
//here, the LHS of condition in if block is the condition which determines minimum number of trailing 0's. This is the same condition that is used to manipulate "v" for getting the same result.
if(min(MP(v[i][j].F+v[i+1][j].F,v[i][j].S+v[i+1][j].S), MP(v[i][j].F+v[i][j+1].F,v[i][j].S+v[i][j+1].S)) == MP(v[i][j].F+v[i+1][j].F,v[i][j].S+v[i+1][j].S))
path[i][j] = 1; //go down
else
path[i][j] = 2; //go right
v[i][j] = min(MP(v[i][j].F+v[i+1][j].F,v[i][j].S+v[i+1][j].S), MP(v[i][j].F+v[i][j+1].F,v[i][j].S+v[i][j+1].S));
}
}
cout<<mini(v[0][0].F, v[0][0].S)<<endl; //print result
for(i=0,j=0;i<=n-1 && j<=n-1;){ //print path (I don't know o/p format)
cout<<"("<<i<<","<<j<<") -> ";
if(path[i][j]==1)
i++;
else
j++;
}
return 0;
}
This code gives fine results as far as the test cases I checked. If you have any doubts regarding this code, ask in comments.
EDIT:
The basic thought process.
To reach the destination, there are only 2 options. I started with destination to avoid the problem of path ahead calculation, because if 2 have same minimum values, then we chose any one of them. If the path to destination is already calculated, it does not matter which we take.
And minimum is to check which pair is more suitable. If a pair has minimum 2's or 5's than other, it will produce less 0's.
Here is a solution proposal using Javascript and functional programming.
It relies on several functions:
the core function is smallest_trailer that recursively goes through the grid. I have chosen to go in 4 possible direction, left "L", right "R", down "D" and "U". It is not possible to pass twice on the same cell. The direction that is chosen is the one with the smallest number of trailing zeros. The counting of trailing zeros is devoted to another function.
the function zero_trailer(p,n,nbz) assumes that you arrive on a cell with a value p while you already have an accumulator n and met nbz zeros on your way. The function returns an array with two elements, the new number of zeros and the new accumulator. The accumulator will be a power of 2 or 5. The function uses the auxiliary function pow_2_5(n) that returns the powers of 2 and 5 inside n.
Other functions are more anecdotical: deepCopy(arr) makes a standard deep copy of the array arr, out_bound(i,j,n) returns true if the cell (i,j) is out of bound of the grid of size n, myMinIndex(arr) returns the min index of an array of 2 dimensional arrays (each subarray contains the nb of trailing zeros and the path as a string). The min is only taken on the first element of subarrays.
MAX_SAFE_INTEGER is a (large) constant for the maximal number of trailing zeros when the path is wrong (goes out of bound for example).
Here is the code, which works on the example given in the comments above and in the orginal link.
var MAX_SAFE_INTEGER = 9007199254740991;
function pow_2_5(n) {
// returns the power of 2 and 5 inside n
function pow_not_2_5(k) {
if (k%2===0) {
return pow_not_2_5(k/2);
}
else if (k%5===0) {
return pow_not_2_5(k/5);
}
else {
return k;
}
}
return n/pow_not_2_5(n);
}
function zero_trailer(p,n,nbz) {
// takes an input two numbers p and n that should be multiplied and a given initial number of zeros (nbz = nb of zeros)
// n is the accumulator of previous multiplications (a power of 5 or 2)
// returns an array [kbz, k] where kbz is the total new number of zeros (nbz + the trailing zeros from the multiplication of p and n)
// and k is the new accumulator (typically a power of 5 or 2)
function zero_aux(k,kbz) {
if (k===0) {
return [1,0];
}
else if (k%10===0) {
return zero_aux(k/10,kbz+1);
}
else {
return [kbz,k];
}
}
return zero_aux(pow_2_5(p)*n,nbz);
}
function out_bound(i,j,n) {
return !((i>=0)&&(i<n)&&(j>=0)&&(j<n));
}
function deepCopy(arr){
var toR = new Array(arr.length);
for(var i=0;i<arr.length;i++){
var toRi = new Array(arr[i].length);
for(var j=0;j<arr[i].length;j++){
toRi[j] = arr[i][j];
}
toR[i] = toRi;
}
return toR;
}
function myMinIndex(arr) {
var min = arr[0][0];
var minIndex = 0;
for (var i = 1; i < arr.length; i++) {
if (arr[i][0] < min) {
minIndex = i;
min = arr[i][0];
}
}
return minIndex;
}
function smallest_trailer(grid) {
var n = grid.length;
function st_aux(i,j,grid_aux, acc_mult, nb_z, path) {
if ((i===n-1)&&(j===n-1)) {
var tmp_acc_nbz_f = zero_trailer(grid_aux[i][j],acc_mult,nb_z);
return [tmp_acc_nbz_f[0], path];
}
else if (out_bound(i,j,n)) {
return [MAX_SAFE_INTEGER,[]];
}
else if (grid_aux[i][j]<0) {
return [MAX_SAFE_INTEGER,[]];
}
else {
var tmp_acc_nbz = zero_trailer(grid_aux[i][j],acc_mult,nb_z) ;
grid_aux[i][j]=-1;
var res = [st_aux(i+1,j,deepCopy(grid_aux), tmp_acc_nbz[1], tmp_acc_nbz[0], path+"D"),
st_aux(i-1,j,deepCopy(grid_aux), tmp_acc_nbz[1], tmp_acc_nbz[0], path+"U"),
st_aux(i,j+1,deepCopy(grid_aux), tmp_acc_nbz[1], tmp_acc_nbz[0], path+"R"),
st_aux(i,j-1,deepCopy(grid_aux), tmp_acc_nbz[1], tmp_acc_nbz[0], path+"L")];
return res[myMinIndex(res)];
}
}
return st_aux(0,0,grid, 1, 0, "");
}
myGrid = [[1, 25, 100],[2, 1, 25],[100, 5, 1]];
console.log(smallest_trailer(myGrid)); //[0,"RDDR"]
myGrid = [[1, 2, 100],[25, 1, 5],[100, 25, 1]];
console.log(smallest_trailer(myGrid)); //[0,"DRDR"]
myGrid = [[1, 10, 1, 1, 1],[1, 1, 1, 10, 1],[10, 10, 10, 10, 1],[10, 10, 10, 10, 1],[10, 10, 10, 10, 1]];
console.log(smallest_trailer(myGrid)); //[0,"DRRURRDDDD"]
This is my Dynamic Programming solution.
https://app.codility.com/demo/results/trainingAXFQ5B-SZQ/
For better understanding we can simplify the task and assume that there are no zeros in the matrix (i.e. matrix contains only positive integers), then the Java solution will be the following:
class Solution {
public int solution(int[][] a) {
int minPws[][] = new int[a.length][a[0].length];
int minPws2 = getMinPws(a, minPws, 2);
int minPws5 = getMinPws(a, minPws, 5);
return min(minPws2, minPws5);
}
private int getMinPws(int[][] a, int[][] minPws, int p) {
minPws[0][0] = pws(a[0][0], p);
//Fullfill the first row
for (int j = 1; j < a[0].length; j++) {
minPws[0][j] = minPws[0][j-1] + pws(a[0][j], p);
}
//Fullfill the first column
for (int i = 1; i < a.length; i++) {
minPws[i][0] = minPws[i-1][0] + pws(a[i][0], p);
}
//Fullfill the rest of matrix
for (int i = 1; i < a.length; i++) {
for (int j = 1; j < a[0].length; j++) {
minPws[i][j] = min(minPws[i-1][j], minPws[i][j-1]) + pws(a[i][j], p);
}
}
return minPws[a.length-1][a[0].length-1];
}
private int pws(int n, int p) {
//Only when n > 0
int pws = 0;
while (n % p == 0) {
pws++;
n /= p;
}
return pws;
}
private int min(int a, int b) {
return (a < b) ? a : b;
}
}

How to perform K-swap operations on an N-digit integer to get maximum possible number

I recently went through an interview and was asked this question. Let me explain the question properly:
Given a number M (N-digit integer) and K number of swap operations(a swap
operation can swap 2 digits), devise an algorithm to get the maximum
possible integer?
Examples:
M = 132 K = 1 output = 312
M = 132 K = 2 output = 321
M = 7899 k = 2 output = 9987
My solution ( algorithm in pseudo-code). I used a max-heap to get the maximum digit out of N-digits in each of the K-operations and then suitably swapping it.
for(int i = 0; i<K; i++)
{
int max_digit_currently = GetMaxFromHeap();
// The above function GetMaxFromHeap() pops out the maximum currently and deletes it from heap
int index_to_swap_with = GetRightMostOccurenceOfTheDigitObtainedAbove();
// This returns me the index of the digit obtained in the previous function
// .e.g If I have 436659 and K=2 given,
// then after K=1 I'll have 936654 and after K=2, I should have 966354 and not 963654.
// Now, the swap part comes. Here the gotcha is, say with the same above example, I have K=3.
// If I do GetMaxFromHeap() I'll get 6 when K=3, but I should not swap it,
// rather I should continue for next iteration and
// get GetMaxFromHeap() to give me 5 and then get 966534 from 966354.
if (Value_at_index_to_swap == max_digit_currently)
continue;
else
DoSwap();
}
Time complexity: O(K*( N + log_2(N) ))
// K-times [log_2(N) for popping out number from heap & N to get the rightmost index to swap with]
The above strategy fails in this example:
M = 8799 and K = 2
Following my strategy, I'll get M = 9798 after K=1 and M = 9978 after K=2. However, the maximum I can get is M = 9987 after K=2.
What did I miss?
Also suggest other ways to solve the problem & ways to optimize my solution.
I think the missing part is that, after you've performed the K swaps as in the algorithm described by the OP, you're left with some numbers that you can swap between themselves. For example, for the number 87949, after the initial algorithm we would get 99748. However, after that we can swap 7 and 8 "for free", i.e. not consuming any of the K swaps. This would mean "I'd rather not swap the 7 with the second 9 but with the first".
So, to get the max number, one would perform the algorithm described by the OP and remember the numbers which were moved to the right, and the positions to which they were moved. Then, sort these numbers in decreasing order and put them in the positions from left to right.
This is something like a separation of the algorithm in two phases - in the first one, you choose which numbers should go in the front to maximize the first K positions. Then you determine the order in which you would have swapped them with the numbers whose positions they took, so that the rest of the number is maximized as well.
Not all the details are clear, and I'm not 100% sure it handles all cases correctly, so if anyone can break it - go ahead.
This is a recursive function, which sorts the possible swap values for each (current-max) digit:
function swap2max(string, K) {
// the recursion end:
if (string.length==0 || K==0)
return string
m = getMaxDigit(string)
// an array of indices of the maxdigits to swap in the string
indices = []
// a counter for the length of that array, to determine how many chars
// from the front will be swapped
len = 0
// an array of digits to be swapped
front = []
// and the index of the last of those:
right = 0
// get those indices, in a loop with 2 conditions:
// * just run backwards through the string, until we meet the swapped range
// * no more swaps than left (K)
for (i=string.length; i-->right && len<K;)
if (m == string[i])
// omit digits that are already in the right place
while (right<=i && string[right] == m)
right++
// and when they need to be swapped
if (i>=right)
front.push(string[right++])
indices.push(i)
len++
// sort the digits to swap with
front.sort()
// and swap them
for (i=0; i<len; i++)
string.setCharAt(indices[i], front[i])
// the first len digits are the max ones
// the rest the result of calling the function on the rest of the string
return m.repeat(right) + swap2max(string.substr(right), K-len)
}
This is all pseudocode, but converts fairly easy to other languages. This solution is nonrecursive and operates in linear worst case and average case time.
You are provided with the following functions:
function k_swap(n, k1, k2):
temp = n[k1]
n[k1] = n[k2]
n[k2] = temp
int : operator[k]
// gets or sets the kth digit of an integer
property int : magnitude
// the number of digits in an integer
You could do something like the following:
int input = [some integer] // input value
int digitcounts[10] = {0, ...} // all zeroes
int digitpositions[10] = {0, ...) // all zeroes
bool filled[input.magnitude] = {false, ...) // all falses
for d = input[i = 0 => input.magnitude]:
digitcounts[d]++ // count number of occurrences of each digit
digitpositions[0] = 0;
for i = 1 => input.magnitude:
digitpositions[i] = digitpositions[i - 1] + digitcounts[i - 1] // output positions
for i = 0 => input.magnitude:
digit = input[i]
if filled[i] == true:
continue
k_swap(input, i, digitpositions[digit])
filled[digitpositions[digit]] = true
digitpositions[digit]++
I'll walk through it with the number input = 724886771
computed digitcounts:
{0, 1, 1, 0, 1, 0, 1, 3, 2, 0}
computed digitpositions:
{0, 0, 1, 2, 2, 3, 3, 4, 7, 9}
swap steps:
swap 0 with 0: 724886771, mark 0 visited
swap 1 with 4: 724876781, mark 4 visited
swap 2 with 5: 724778881, mark 5 visited
swap 3 with 3: 724778881, mark 3 visited
skip 4 (already visited)
skip 5 (already visited)
swap 6 with 2: 728776481, mark 2 visited
swap 7 with 1: 788776421, mark 1 visited
swap 8 with 6: 887776421, mark 6 visited
output number: 887776421
Edit:
This doesn't address the question correctly. If I have time later, I'll fix it but I don't right now.
How I would do it (in pseudo-c -- nothing fancy), assuming a fantasy integer array is passed where each element represents one decimal digit:
int[] sortToMaxInt(int[] M, int K) {
for (int i = 0; K > 0 && i < M.size() - 1; i++) {
if (swapDec(M, i)) K--;
}
return M;
}
bool swapDec(int[]& M, int i) {
/* no need to try and swap the value 9 as it is the
* highest possible value anyway. */
if (M[i] == 9) return false;
int max_dec = 0;
int max_idx = 0;
for (int j = i+1; j < M.size(); j++) {
if (M[j] >= max_dec) {
max_idx = j;
max_dec = M[j];
}
}
if (max_dec > M[i]) {
M.swapElements(i, max_idx);
return true;
}
return false;
}
From the top of my head so if anyone spots some fatal flaw please let me know.
Edit: based on the other answers posted here, I probably grossly misunderstood the problem. Anyone care to elaborate?
You start with max-number(M, N, 1, K).
max-number(M, N, pos, k)
{
if k == 0
return M
max-digit = 0
for i = pos to N
if M[i] > max-digit
max-digit = M[i]
if M[pos] == max-digit
return max-number(M, N, pos + 1, k)
for i = (pos + 1) to N
maxs.add(M)
if M[i] == max-digit
M2 = new M
swap(M2, i, pos)
maxs.add(max-number(M2, N, pos + 1, k - 1))
return maxs.max()
}
Here's my approach (It's not fool-proof, but covers the basic cases). First we'll need a function that extracts each DIGIT of an INT into a container:
std::shared_ptr<std::deque<int>> getDigitsOfInt(const int N)
{
int number(N);
std::shared_ptr<std::deque<int>> digitsQueue(new std::deque<int>());
while (number != 0)
{
digitsQueue->push_front(number % 10);
number /= 10;
}
return digitsQueue;
}
You obviously want to create the inverse of this, so convert such a container back to an INT:
const int getIntOfDigits(const std::shared_ptr<std::deque<int>>& digitsQueue)
{
int number(0);
for (std::deque<int>::size_type i = 0, iMAX = digitsQueue->size(); i < iMAX; ++i)
{
number = number * 10 + digitsQueue->at(i);
}
return number;
}
You also will need to find the MAX_DIGIT. It would be great to use std::max_element as it returns an iterator to the maximum element of a container, but if there are more you want the last of them. So let's implement our own max algorithm:
int getLastMaxDigitOfN(const std::shared_ptr<std::deque<int>>& digitsQueue, int startPosition)
{
assert(!digitsQueue->empty() && digitsQueue->size() > startPosition);
int maxDigitPosition(0);
int maxDigit(digitsQueue->at(startPosition));
for (std::deque<int>::size_type i = startPosition, iMAX = digitsQueue->size(); i < iMAX; ++i)
{
const int currentDigit(digitsQueue->at(i));
if (maxDigit <= currentDigit)
{
maxDigit = currentDigit;
maxDigitPosition = i;
}
}
return maxDigitPosition;
}
From here on its pretty straight what you have to do, put the right-most (last) MAX DIGITS to their places until you can swap:
const int solution(const int N, const int K)
{
std::shared_ptr<std::deque<int>> digitsOfN = getDigitsOfInt(N);
int pos(0);
int RemainingSwaps(K);
while (RemainingSwaps)
{
int lastHDPosition = getLastMaxDigitOfN(digitsOfN, pos);
if (lastHDPosition != pos)
{
std::swap<int>(digitsOfN->at(lastHDPosition), digitsOfN->at(pos));
++pos;
--RemainingSwaps;
}
}
return getIntOfDigits(digitsOfN);
}
There are unhandled corner-cases but I'll leave that up to you.
I assumed K = 2, but you can change the value!
Java code
public class Solution {
public static void main (String args[]) {
Solution d = new Solution();
System.out.println(d.solve(1234));
System.out.println(d.solve(9812));
System.out.println(d.solve(9876));
}
public int solve(int number) {
int[] array = intToArray(number);
int[] result = solve(array, array.length-1, 2);
return arrayToInt(result);
}
private int arrayToInt(int[] array) {
String s = "";
for (int i = array.length-1 ;i >= 0; i--) {
s = s + array[i]+"";
}
return Integer.parseInt(s);
}
private int[] intToArray(int number){
String s = number+"";
int[] result = new int[s.length()];
for(int i = 0 ;i < s.length() ;i++) {
result[s.length()-1-i] = Integer.parseInt(s.charAt(i)+"");
}
return result;
}
private int[] solve(int[] array, int endIndex, int num) {
if (endIndex == 0)
return array;
int size = num ;
int firstIndex = endIndex - size;
if (firstIndex < 0)
firstIndex = 0;
int biggest = findBiggestIndex(array, endIndex, firstIndex);
if (biggest!= endIndex) {
if (endIndex-biggest==num) {
while(num!=0) {
int temp = array[biggest];
array[biggest] = array[biggest+1];
array[biggest+1] = temp;
biggest++;
num--;
}
return array;
}else{
int n = endIndex-biggest;
for (int i = 0 ;i < n;i++) {
int temp = array[biggest];
array[biggest] = array[biggest+1];
array[biggest+1] = temp;
biggest++;
}
return solve(array, --biggest, firstIndex);
}
}else{
return solve(array, --endIndex, num);
}
}
private int findBiggestIndex(int[] array, int endIndex, int firstIndex) {
int result = firstIndex;
int max = array[firstIndex];
for (int i = firstIndex; i <= endIndex; i++){
if (array[i] > max){
max = array[i];
result = i;
}
}
return result;
}
}

Find the amount of water in ith cup in a pyramid structure?

This question was asked in a forum. Any suggestions?
There is a pyramid with 1 cup at level , 2 at level 2 , 3 at level 3 and so on..
It looks something like this
1
2 3
4 5 6
every cup has capacity C. you pour L liters of water from top . when cup 1 gets filled , it overflows to cup 2,3 equally, and when they get filled , Cup 4 and 6 get water only from 2 and 3 resp but 5 gets water from both the cups and so on.
Now given C and L .Find the amount of water in ith cup ?
Each glass has an incoming flow, an amount of water in the glass, and maybe some outgoing flow (overflow).
If each glass can contain 1 unit of water, and you pour 15 units of water, you get the following (overflow amount in parenthesis):
Incoming flow = 15, capacity = 1
Level 1: 1(14)
Level 2: 1(6) 1(6)
Level 3: 1(2) 1(5) 1(2)
Level 4: 1(1) 1(2.5) 1(2.5) 1(1)
Level 5: 1 1(0.75) 1(1.5) 1(0.75) 1
Level 6: 0 0.375 1(0.125) 1(0.125) 0.375 0
Level 7: 0 0 0.0625 0.125 0.0625 0 0
The incoming flow to the first level is L. The incoming flow from glass c on level r is Fin(c, r), and could be written as:
Fin(0, r) = 0
Fin(r+1, r) = 0
Fin(1, 1) = L
Fin(c, r) = Fout(c - 1, r - 1)/2 + Fout(c, r - 1)/2
The amount of water in that glass is:
A(c, r) = Min(C, Fin(c, r))
And the outgoing flow is:
Fout(c, r) = Max(0, Fin(c, r) - C)
I don't see any obvious formula for evaluating A(c, r) without doing it recursively.
To get from an index to a row and glass position, you can do:
index = r*(r-1)/2 + c
r = floor((1 + sqrt(8*index - 7))/2)
c = index - r*(r-1)/2
(indexes start with 1)
If you model the pyramid into a graph, the problem converts into a breadth first search. As you traverse each node, get its neighbours and store their overflow quantity. If a neighbour was already retrieved by a previous node (this will happen in the case of 5 node because node 2 and node 3 have an edge to it), you will have to update the overflow based on its capacity and what's already been filled (by node 2; assuming node 2 was traversed before node 3).
Some ideas:
(1) The important is knowing which two cups are inputs to the ith cup.
(2) The important is know the Minimum Lleft that will bring you water from your left side and what level Lright will bring you water from your right side
(3) So you need to know which cups provide water to cup ith. This is easier, thinking quick, if you start numbering from 0. Cup ith will fill (i-1)*2+1 and i*2, what means that cup kth will receive water from (for k%2=1) (k-1)/2 and (k+1)/2 (for k%2=0) k/2 and k/2+1
(4) With that you should check that for any L you will calculate the difference L-Lleft and L-Lright. When positive the water provided is the result of dividing by 2^n the calculated difference, where n is the level of the cup.
The pascal triangle solution for calculating binomial coefficient can be used to solve this problem. We just need to tweak the algorithm a little bit and instead of calculating binomial coefficients, we calculate the water level. Given ith cup, we calculate level and index to find out where the cup sits in the triangle.
The cups are modelled as
0 Level 1
1 2 Level 2
3 4 5 Level 3
getIndex() and getLevel() returns the index and level. Index and Level starts at 1.
public static int getIndex(int i) {
int totalNodes = i + 1;
double d = (-3 + Math.sqrt(9 - 8*(1-totalNodes)))/2;
int level = (int)Math.floor(d);
int total = ((level+1)*(level+2))/2;
int index = 0;
if(total==totalNodes) index = level;
else{
level++;
index = totalNodes - total - 1;
}
return ++index;
}
public static int getLevel(int i) {
int totalNodes = i + 1;
double d = (-3 + Math.sqrt(9 - 8*(1-totalNodes)))/2;
int level = (int)Math.floor(d);
int total = ((level+1)*(level+2))/2;
int index = 0;
if(total==totalNodes) index = level;
else{
level++;
index = totalNodes - total - 1;
}
return ++level;
}
k is kth cup starting at 0. C is cup capacity, L is total water.
public static double getWaterLevel(double C, double L, int k) {
int n = getLevel(k);
int index = getIndex(k);
double[] water = new double[index+1];
water[1] = L;
for(int i = 2; i <= n; i++)
{
boolean overflowed = false;
for(int j = Math.min(i, index); j > 0; j--) {
double over = 0;
if(water[j]>C) over = (water[j]-C)/2;
if(water[j-1]>C) over += (water[j-1]-C)/2;
water[j] = over;
if(!overflowed && over!=0) overflowed=true;
}
if(!overflowed) break; // no more overflow. stop
}
return water[index] > C ? C : water[index];
}
Here is another easy solution that simply pours the water into the current glass and then checks if there is extra water then flows to the next level. Here I have used 2D Mat for pouring the water. Then I have converted the 2D mat to 1D having size equals to ith element/glass which we need to return and return that. Implementation wise this is a very easy solution.
private double fillWaterInGlasses(double capacity, double water , int glassToFind) {
int maxLevel = (int)(water/capacity)/2 + 1;
double[][] glasses = new double[maxLevel][maxLevel];
// Pour total water in top glass initially.
glasses[0][0] = water;
int level=0;
boolean waterInLevel = true;
while(waterInLevel) {
waterInLevel = false;
// For each glass in the level.
for(int j=0; j<=level; j++) {
// If the glass has more liquid then it can store then pour it to glasses under it.
if(glasses[level][j] > capacity) {
double extraWater = glasses[level][j] - capacity;
glasses[level][j] = capacity;
glasses[level+1][j] += extraWater / 2;
glasses[level+1][j+1] += extraWater / 2;
waterInLevel = true;
}
}
level++;
}
double res[] = new double[glassToFind];
int k =0;
for (int i = 0; i < glasses.length; i++) {
for (int j = 0; j <= i; j++) {
res[k] = glasses[i][j];
if (k == glassToFind-1){
return res[glassToFind-1];
}
k++;
}
}
return res[glassToFind-1];
}
Here is a simple and comprehensible implementation:
public class main {
static float total_water = 50;
static int N = 20;
static glass[][] pyramid = new glass[N][N];
public static void main(String[] args) {
build_pyramid();
pour_water(0, 0, total_water);
print_pyramid();
print_total_water_stored();
}
private static void print_total_water_stored() {
float total = 0;
for (int i = 0; i < N; i++) {
for (int j = 0; j <= i; j++)
total += pyramid[i][j].filled;
}
System.out.println("total water stored= " + total);
}
private static void pour_water(int row, int col, float water) {
if (water >= (pyramid[row][col].capacity - pyramid[row][col].filled)) {
water -= (pyramid[row][col].capacity - pyramid[row][col].filled);
pyramid[row][col].filled = pyramid[row][col].capacity;
pour_water(row + 1, col, water / 2);
pour_water(row + 1, col + 1, water / 2);
} else {
pyramid[row][col].filled += water;
}
}
public static void build_pyramid() {
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++)
pyramid[i][j] = new glass(1);
}
}
public static void print_pyramid() {
for (int i = 0; i < N; i++) {
for (int j = 0; j <= i; j++)
System.out.print(pyramid[i][j].filled + " ");
System.out.println();
}
}
}
class glass {
float capacity;
float filled;
glass(float cap) {
capacity = cap;
filled = 0;
}
}

Resources