Dynamic Programming: Find possible ways to reach destination - algorithm

I'm trying to solve this problem, O(N^2) solution is simple, O(N) is possible, but I cannot think of how. Here's the question:
There are N cities and N directed roads in Steven's world. The cities are numbered from 0 to N - 1. Steven can travel from city i to city (i + 1) % N, ( 0-> 1 -> 2 -> .... -> N - 1 -> 0).
Steven wants to travel around the world by car. The capacity of his car's fuel tank is C gallons. There are a[i] gallons he can use at the beginning of city i and the car takes b[i] gallons to travel from city i to (i + 1) % N.
How many cities can Steven start his car from so that he can travel around the world and reach the same city he started?
Note
The fuel tank is initially empty.
Input Format
The first line contains two integers (separated by a space): city number N and capacity C.
The second line contains N space-separated integers: a[0], a[1], … , a[N - 1].
The third line contains N space-separated integers: b[0], b[1], … , b[N - 1].
Output Format
The number of cities which can be chosen as the start city.
Sample Input
3 3
3 1 2
2 2 2
Sample Output
2
Explanation
Steven starts from city 0, fills his car with 3 gallons of fuel, and use 2 gallons of fuel to travel to city 1. His fuel tank now has 1 gallon of fuel.
On refueling 1 gallon of fuel at city 1, he then travels to city 2 by using 2 gallons of fuel. His fuel tank is now empty.
On refueling 2 gallon of fuel at city 2, he then travels back to city 0 by using 2 gallons of fuel.
Here is the second possible solution.
Steven starts from city 2, fill his car with 2 gallons, and travels to city 0.
On refueling 3 gallons of fuel from city 0, he then travels to city 1, and exhausts 2 gallons of fuel. His fuel tank contains 1 gallon of fuel now. He can then refuel 1 gallon of fuel at City 1, and increase his car's fuel to 2 gallons and travel to city 2.
However, Steven cannot start from city 1, because he is given only 1 gallon of fuel, but travelling to city 2 requires 2 gallons.
Hence the answer 2.
Now I know this algorithm could be solved in O(N) time complexity, which I am unable to, guess it can be solved using dynamic programming, please help me get a clue how it could be broken into sub problems.

I've made and an algorithm that should solve the problem, it outputs 2 for your case, but it must be tested on other testcases.
I'm not sure it's correct. My main idea was that if you can make an iteration starting from one point you can make how many you wish, and the reverse is also true. If you can't make more than one, you cannot make even one.
#include <algorithm>
#include <iostream>
using namespace std;
#define PROB_SIZE 3
int n = PROB_SIZE, c = 3;
int a[PROB_SIZE] = {3, 1, 2}; // available
int b[PROB_SIZE] = {2, 2, 2}; // used
int d[PROB_SIZE];
int dmin[PROB_SIZE];
int main()
{
//The fuel used in the trip to next node (amount put in minus the amount consumed in one trip).
for (int i = 0; i < n; i++) {
d[i] = a[i] - b[i];
}
//The fuel that i need to start a trip in this point and reach point 0.
dmin[n - 1] = d[n - 1];
for (int i = n - 2; i >= 0; i--) {
dmin[i] = min(d[i], d[i] + dmin[i + 1]);
}
//The second loop to be sure i cover a whole loop from any point.
dmin[n - 1] = min(d[n - 1], d[n - 1] + dmin[0]);
for (int i = n - 2; i >= 0; i--) {
dmin[i] = min(d[i], d[i] + dmin[i + 1]);
}
//If for any point i need to have more fuel than i can carry then the trip is impossible for all points.
for (int i = 0; i < n; i++) {
if ((-dmin[i] + a[i]) > c) {
cout << 0 << endl;
return 0;
}
}
int cnt = 0;
//Any point that i need to have 0 fuel to reach point 0 making at least one round trip is a good starting point.
for (int i = 0; i < n; i++) {
if (dmin[i] >= 0) {
cnt++;
}
}
cout << cnt << endl;
}

First, I would like to point out that this question is word-for-word lifted from an exercise on HackerRank.
Here's a sketch of an algorithm that has been confirmed to pass all test cases on that site for this particular problem in O(N) time.
For all partial "trips" starting from 0 and ending at i for 0 < i < N, compute the following information:
What is the minimal gas we need to begin the trip at city 0 in order to successfully go from 0 to i?
Starting with this minimal amount (assuming the partial trip is even possible) how much gas will we have as we enter city i?
During such a trip, what is the largest amount of gas you will ever carry in your tank?
The reason we need #3 is because of the limited gas tank capacity sometimes prevents us from taking the "gas profile" of some trip and just "shifting everything up". Knowing how close we are to the ceiling for some given trip tells us exactly how much we can "shift up" before we hit the ceiling. (This sounds vague, but one should think about this point closely).
Once you have these three for every 0 < i < N, you also must compute these three for all partial trips starting at some i with 0 < i < N and wrapping around back to zero.
All six of these figures of merit can be computed in O(1) time per city using some slightly clever dynamic programming, and once you have them all for all the cities, it takes O(1) time to check if a city can wrap around completely.
Here is the python implementation of above idea:
def travelAroundTheWorld(a, b, c):
a = [min(i,c) for i in a]
if max(b) > c:
return 0
min_req, max_reached, remaining_cap,Min_req, Max_reached, Remaining_cap= ([0]*(len(a)+1) for _ in range(6))
for i in range(1,len(a)):
if b[i-1] > a[i-1]+remaining_cap[i-1]:
if c-max_reached[i-1] < b[i-1]-remaining_cap[i-1]-a[i-1]:
return 0
min_req[i] = min_req[i-1] + b[i-1]-remaining_cap[i-1]-a[i-1]
remaining_cap[i] = 0
max_reached[i] = max(max_reached[i-1]+b[i-1]-remaining_cap[i-1]-a[i-1],b[i-1])
else:
min_req[i] = min_req[i-1]
remaining_cap[i] = min(remaining_cap[i-1]+a[i-1], c) - b[i-1]
max_reached[i] = max(max_reached[i-1],min(remaining_cap[i-1]+a[i-1], c))
for i in range(len(a)-1,0,-1):
if Min_req[i+1] + b[i] > c:
return 0
if b[i] > a[i]:
Min_req[i] = Min_req[i+1] + b[i]-a[i]
Remaining_cap[i] = Remaining_cap[i+1]
Max_reached[i] = max(Max_reached[i+1], a[i]+Min_req[i])
elif a[i]-b[i]>Min_req[i+1]:
Min_req[i] = 0
Remaining_cap[i] = Remaining_cap[i+1] + min(c-Max_reached[i+1], a[i]-b[i]-Min_req[i+1])
Max_reached[i] = max(a[i], min(c, Max_reached[i+1]+a[i]-b[i]-Min_req[i+1]))
else:
Min_req[i] = Min_req[i+1] + b[i]-a[i]
Remaining_cap[i] = Remaining_cap[i+1]
Max_reached[i] = max(Max_reached[i+1], Min_req[i]+a[i])
ans = 0
if min_req[1] == 0 and remaining_cap[1] >= Min_req[1]:
ans = 1
for i in range(1,len(a)):
if Min_req[i] == 0 and Remaining_cap[i] >= min_req[i]:
ans += 1
return ans

While you try to find out whether you can get from city i back to city i, you need to gather information about previous cities. I'd create a stack containing information that you could start at city x, and arrive at city y with z fuel in the tank.
When you check out city j, you find that you can put X fuel in the tank at j, and driving to j+1 takes Y fuel. If X >= Y, you put that information on the stack. Otherwise, pop the top of the stack. The information there will tell you that you could start at some x and arrive at j with z fuel in the tank. Starting at x, you would leave j with min (z + X, C) in the tank. If that is enough, push the information back on the stack. If not, pop the next item from the stack. If the stack is empty, there is no way to reach j+1.
Now you need to figure out how to end the search, and prove that there are only O (N) operations.

Simpler method: You have your list of cities, and one by one you remove the ones where you cannot start.
You look for the first city i that hasn't enough fuel to get to city i+1. If there is no such city, you can start anywhere. Since you can't get from i to i+1, you remove it from the list of cities, but you need to combine it with the previous one. If the previous city has x fuel and needs y, x >= y, and city i has X fuel and needs Y you do the following:
Replace X with min (X, C - (x - y)) (because the extra fuel can't be used).
Subtract min (y, X) from y and X (because that's you much you can refill)
Replace x with min (C, x + X) and y with y + Y.
At that point, you check the previous city again. You finish when you can go from each city to the next. You may end up with one city that can't reach the next one; in that case you fail.

static int n = 3;
static int c = 3;
static int a[] = {3, 1, 2};
static int b[] = {2, 2, 2};
static int currentCity;
public static void main(String[] args) {
List<String> citi = new ArrayList<String>();
//try one by one
for(int i = 0; i < n; i ++){
currentCity = i;
if(!startFrom(i, 0))
continue;
citi.add("citi" + i);
}
for (String s: citi)
System.out.println(s);
}
public static boolean startFrom(int i, int left){
int tankVal = (a[i] + left) > c ? c : (a[i] + left);
if(b[i] > tankVal)
return false;
left = tankVal - b[i];
int next = (i + 1) % n;
if(next == currentCity)
return true;
return startFrom(next, left);
}

Related

How to deal with Dynamic Programming problems where the current actions allowed depends on a previously done action?

I am beginning to solve DP problems by tabulation, and I am curious as to how to deal with such questions. For example, these type of questions: https://atcoder.jp/contests/dp/tasks/dp_c, http://www.usaco.org/index.php?page=viewproblem2&cpid=574, and also https://cses.fi/problemset/task/1097. Normally in the top down version of such problems, a flag is passed down to the next function call so the program knows not to repeat the same action, for example like passing a flag denoting that activity 0 was previously chosen (Vacation question), passing a flag denoting that the water has already been drank (Fruit Feast question), passing a flag denoting whose turn it is (Removal Game question), but how is this done in the bottom up version? I am not looking for a solution to these problems as I have already done them, but instead sort of a general idea to deal with such problems in a bottom up manner where an action depends on the previous actions done or where an action can only be done once. Thank you in advance.
For those who cannot access the links:
Link 1:
Problem Statement
Taro's summer vacation starts tomorrow, and he has decided to make plans for it now.
The vacation consists of N days. For each i (1≤i≤N), Taro will choose one of the following activities and do it on the i-th day:
A: Swim in the sea. Gain a i points of happiness. B: Catch bugs in the mountains. Gain b i points of happiness.
C: Do homework at home. Gain c i points of happiness.
As Taro gets bored easily, he cannot do the same activities for two or more consecutive days. Find the maximum possible total points of happiness that Taro gains.
Constraints
All values in input are integers.
1≤N≤10
5
1≤a
i
​
,b
i
​
,c
i
​
≤10
4
Link 2: Problem Statement
Bessie has broken into Farmer John's house again! She has discovered a pile of lemons and a pile of oranges in the kitchen (effectively an unlimited number of each), and she is determined to eat as much as possible.
Bessie has a maximum fullness of T (1≤T≤5,000,000). Eating an orange increases her fullness by A, and eating a lemon increases her fullness by B (1≤A,B≤T). Additionally, if she wants, Bessie can drink water at most one time, which will instantly decrease her fullness by half (and will round down).
Help Bessie determine the maximum fullness she can achieve!
Link 3 : Problem Statement
There is a list of n numbers and two players who move alternately. On each move, a player removes either the first or last number from the list, and their score increases by that number. Both players try to maximize their scores.
What is the maximum possible score for the first player when both players play optimally?
Constraints:
1≤n≤5000
−10^9≤xi≤10^9
(For problems 2 and 3 I read solutions posted online and describe my understanding and code versions below. For problem 1, I did not look up a solution online.)
For problem 1 (Taro's summer vacation), we have the state at the end of activities as dp[i] = [a, b, c], where each element of the tuple, [a, b, c], indicates the most points of happiness if Taro performs that activity on the ith day. Since we are not allowed two consecutive days of the same activity, the state of each day as activity X is dependent on the other two activities the day before.
dp[0] = [A[0], B[0], C[0]]
dp[i][0] = A[i] + max(dp[i-1][1], dp[i-1][2])
dp[i][1] = B[i] + max(dp[i-1][0], dp[i-1][2])
dp[i][2] = C[i] + max(dp[i-1][0], dp[i-1][1])
function f(ABC){
const n = ABC.length;
const dp = [];
dp[0] = ABC[0];
for (let i=1; i<n; i++){
dp[i] = [0, 0, 0];
dp[i][0] = ABC[i][0] + Math.max(dp[i-1][1], dp[i-1][2]);
dp[i][1] = ABC[i][1] + Math.max(dp[i-1][0], dp[i-1][2]);
dp[i][2] = ABC[i][2] + Math.max(dp[i-1][0], dp[i-1][1]);
}
return Math.max(dp[n-1][0], dp[n-1][1], dp[n-1][2])
}
var ABC = [
[10, 40, 70],
[20, 50, 80],
[30, 60, 90]
];
for (row of ABC)
console.log(String(row));
console.log(f(ABC));
For problem 2 (Bessie's fullness), our dp state is two dimensional booleans, one for before halving the fullness and one for after, dp[i] = [before, after]. dp[i][0] (before halving the fullness) is achievable if we can arrive at it by having added either A or B. dp[i/2][1] (after halving the fullness) is achievable if dp[i][0] was achievable.
dp[0] = [true, true]
dp[i][0] = dp[i - A][0] OR dp[i - B][0]
dp[i/2][1] = dp[i][0]
Perform another run for after the fullness is halved.
dp[i][1] = dp[i - A][1] OR dp[i - B][1]
function f(T, A, B){
const dp = [];
dp[0] = [true, true];
for (let i=1; i<=T; i++){
dp[i] = [false, false];
dp[i][0] ||= i - A >= 0 && dp[i - A][0];
dp[i][0] ||= i - B >= 0 && dp[i - B][0];
dp[Math.floor(i/2)][1] = dp[i][0];
}
for (let i=0; i<=T; i++){
dp[i][1] ||= i - A >= 0 && dp[i - A][1];
dp[i][1] ||= i - B >= 0 && dp[i - B][1];
}
for (let i=T; i>=0; i--)
if (dp[i][1])
return i;
}
var T = 8;
var A = 5;
var B = 6;
console.log(String([T, A, B]));
console.log(f(T, A, B));
For problem 3 (maximise score), player 1 wants to maximise score_1 - score_2 and player 2 wants to minimise score_1 - score_2. Our dp state for the current interval, dp[left][right] describes score_1 - score_2. dp[left][right] when left equals right is the score player 1 gets for taking that single element:
dp[i][i] = A[i]
Otherwise, we consider what happens if player 1 takes each side.
If player 1 takes A[l], we are left with the interval dp[l + 1][r], which is the score achivable by player 2 since it's their turn. So score_1 - score_2 will be:
A[l] - dp[l + 1][r]
And if player 1 takes A[r], the score player 2 will achieve is dp[l][r - 1], and score_1 - score_2 will be:
A[r] - dp[l][r - 1]
Of course, player 1 would like the maximum of these two options:
dp[l][r] = max(A[l] - dp[l + 1][r], A[r] - dp[l][r - 1])
function f(A){
const n = A.length;
const dp = [];
let total = 0;
for (let i=0; i<n; i++){
dp[i] = new Array(n).fill(0);
dp[i][i] = A[i];
total += A[i];
}
for (let l=n-2; l>=0; l--)
for (let r=l+1; r<n; r++)
dp[l][r] = Math.max(A[l] - dp[l + 1][r], A[r] - dp[l][r - 1]);
// total + difference
// = (score_1 + score_2) + (score_1 - score_2)
// = score_1 + score_1
// return (score_1 + score_1) / 2
return (total + dp[0][n-1]) / 2;
}
var A = [4, 5, 1, 3];
console.log(String(A));
console.log(f(A));

Dynamic Programming for Matching Size (least difference)

I found this problem which seeks to use dynamic programming to minimize the absolute difference between height for n boys and m girls in a match.
If I understand it correctly we will be sorting the first j boys and k girls by height (ascending? or descending?) where j<=k. Why is j <=k?
I do not understand how I can use the recurrence mentioned in the link:
(j,k−1) and (j−1,k−1)
to find the optimal matching for the values (j,k), based on whether you pair up boy j with girl k or not.
I'm clearly misunderstanding some things here but my goal is to write pseudo code for this solution. Here are my steps:
1. Sort heights Array[Boys] and Array[Girls]
2. To pair Optimally for the least absolute difference in height, simply pair in order so Array[Pairs][1] = Array[Boys][1] + Array[Girls][1]
3. Return which boy was paired with which girl
Please help me to implement the solution proposed in the link.
As stated in the answer you provided, there is always a better matching available if there is a cross edge between two matchings, when the heights are sorted for all the boys and all the girls in ascending order.
So a Dynamic programming solution with complexity of O(n*m) is possible.
So we have a state represented by 2 indexes, lets call them i and j, where i refers for boys and j refers to the girls, then at each state (i, j) we can make a move to the state (i, j+1), i.e. the current ith boy does not choose the current jth girl or the move can be made to the state (i+1, j+1), i.e. the current jth girl is chosen by the current ith boy and we choose the minimum between these two choices at every level.
This can be easily implemented using a DP solution.
Reccurrence :
DP[i][j] = minimum(
DP[i+1][j+1] + abs(heightOfBoy[i] - heightofGirl[j]),
DP[i][j+1]
);
Below is the code in c++ for recursive DP Solution :
#include<bits/stdc++.h>
#define INF 1e9
using namespace std;
int n, m, htB[100] = {10,10,12,13,16}, htG[100] = {6,7,9,10,11,12,17}, dp[100][100];
int solve(int idx1, int idx2){
if(idx1 == n) return 0;
if(idx2 == m) return INF;
if(dp[idx1][idx2] != -1) return dp[idx1][idx2];
int v1, v2;
//include current
v1 = solve(idx1 + 1, idx2 + 1) + abs(htB[idx1] - htG[idx2]);
//do not include current
v2 = solve(idx1, idx2 + 1);
return dp[idx1][idx2] = min(v1, v2);
}
int main(){
n = 5, m = 7;
sort(htB, htB+n);sort(htG, htG+m);
for(int i = 0;i < 100;i++) for(int j = 0;j < 100;j++) dp[i][j] = -1;
cout << solve(0, 0) << endl;
return 0;
}
Output : 4
Link to solution on Ideone : http://ideone.com/K5FZ9x
The DP table output of the above solution :
4 4 4 1000000000 1000000000 1000000000 1000000000
-1 3 3 3 1000000000 1000000000 1000000000
-1 -1 3 3 3 1000000000 1000000000
-1 -1 -1 2 2 2 1000000000
-1 -1 -1 -1 1 1 1
The answer is stored in the DP[0][0] state.
You could turn that problem into a bipartite graph where the edge between a girl and a boy is the absolute difference between their heights like so abs(hG - hB). Then you can use the bipartite matching algorithm to solve for a minimal matching. See this for more info http://www.geeksforgeeks.org/maximum-bipartite-matching/

No of ways to walk M steps in a grid

You are situated in an grid at position x,y. The dimensions of the row is dx,dy. In one step, you can walk one step ahead or behind in the row or the column. In how many ways can you take M steps such that you do not leave the grid at any point ?You can visit the same position more than once.
You leave the grid if you for any x,y either x,y <= 0 or x,y > dx,dy.
1 <= M <= 300
1 <= x,y <= dx,dy <= 100
Input:
M
x y
dx dy
Output:
no of ways
Example:
Input:
1
6 6
12 12
Output:
4
Example:
Input:
2
6 6
12 12
Output:
16
If you are at position 6,6 then you can walk to (6,5),(6,7),(5,6),(7,6).
I am stuck at how to use Pascal's Triangle to solve it.Is that the correct approach? I have already tried brute force but its too slow.
C[i][j], Pascal Triangle
C[i][j] = C[i - 1][j - 1] + C[i - 1][j]
T[startpos][stp]
T[pos][stp] = T[pos + 1][stp - 1] + T[pos - 1][stp - 1]
You can solve 1d problem with the formula you provided.
Let H[pos][step] be number of ways to move horizontal using given number of steps.
And V[pos][step] be number of ways to move vertical sing given number of steps.
You can iterate number of steps that will be made horizontal i = 0..M
Number of ways to move so is H[x][i]*V[y][M-i]*C[M][i], where C is binomial coefficient.
You can build H and V in O(max(dx,dy)*M) and do second step in O(M).
EDIT: Clarification on H and V. Supppose that you have line, that have d cells: 1,2,...,d. You're standing at cell number pos then T[pos][step] = T[pos-1][step-1] + T[pos+1][step-1], as you can move either forward or backward.
Base cases are T[0][step] = 0, T[d+1][step] = 0, T[pos][0] = 1.
We build H assuming d = dx and V assuming d = dy.
EDIT 2: Basically, the idea of algorithm is since we move in one of 2 dimensions and check is also based on each dimension independently, we can split 2d problem in 2 1d problems.
One way would be an O(n^3) dynamic programming solution:
Prepare a 3D array:
int Z[dx][dy][M]
Where Z[i][j][n] holds the number of paths that start from position (i,j) and last n moves.
The base case is Z[i][j][0] = 1 for all i, j
The recursive case is Z[i][j][n+1] = Z[i-1][j][n] + Z[i+1][j][n] + Z[i][j-1][n] + Z[i][j+1][n] (only include terms in the sumation that are on the map)
Once the array is filled out return Z[x][y][M]
To save space you can discard each 2D array for n after it is used.
Here's a Java solution I've built for the original hackerrank problem. For big grids runs forever. Probably some smart math is needed.
long compute(int N, int M, int[] positions, int[] dimensions) {
if (M == 0) {
return 1;
}
long sum = 0;
for (int i = 0; i < N; i++) {
if (positions[i] < dimensions[i]) {
positions[i]++;
sum += compute(N, M - 1, positions, dimensions);
positions[i]--;
}
if (positions[i] > 1) {
positions[i]--;
sum += compute(N, M - 1, positions, dimensions);
positions[i]++;
}
}
return sum % 1000000007;
}

Find the a location in a matrix so that the cost of every one moving to that location is smallest

There is a matrix, m×n. Several groups of people locate at some certain spots. In the following example, there are three groups and the number 4 indicates there are four people in this group. Now we want to find a meeting point in the matrix so that the cost of all groups moving to that point is the minimum. As for how to compute the cost of moving one group to another point, please see the following example.
Group1: (0, 1), 4
Group2: (1, 3), 3
Group3: (2, 0), 5
. 4 . .
. . . 3
5 . . .
If all of these three groups moving to (1, 1), the cost is:
4*((1-0)+(1-1)) + 5*((2-1)+(1-0))+3*((1-1)+(3-1))
My idea is :
Firstly, this two dimensional problem can be reduced to two one dimensional problem.
In the one dimensional problem, I can prove that the best spot must be one of these groups.
In this way, I can give a O(G^2) algorithm.(G is the number of group).
Use iterator's example for illustration:
{(-100,0,100),(100,0,100),(0,1,1)},(x,y,population)
for x, {(-100,100),(100,100),(0,1)}, 0 is the best.
for y, {(0,100),(0,100),(1,1)}, 0 is the best.
So it's (0, 0)
Is there any better solution for this problem.
I like the idea of noticing that the objective function can be decomposed to give the sum of two one-dimensional problems. The remaining problems look a lot like the weighted median to me (note "solves the following optimization problem in "http://www.stat.ucl.ac.be/ISdidactique/Rhelp/library/R.basic/html/weighted.median.html" or consider what happens to the objective function as you move away from the weighted median).
The URL above seems to say the weighted median takes time n log n, which I guess means that you could attain their claim by sorting the data and then doing a linear pass to work out the weighted median. The numbers you have to sort are in the range [0, m] and [0, n] so you could in theory do better if m and n are small, or - of course - if you are given the data pre-sorted.
Come to think of it, I don't see why you shouldn't be able to find the weighted median with a linear time randomized algorithm similar to that used to find the median (http://en.wikibooks.org/wiki/Algorithms/Randomization#find-median) - repeatedly pick a random element, use it to partition the items remaining, and work out which half the weighted median should be in. That gives you expected linear time.
I think this can be solved in O(n>m?n:m) time and O(n>m?n:m) space.
We have to find the median of x coordinates and median of all y coordinates in the k points and the answer will be (x_median,y_median);
Assumption is this function takes in the following inputs:
total number of points :int k= 4+3+5 = 12;
An array of coordinates:
struct coord_t c[12] = {(0,1),(0,1),(0,1), (0,1), (1,3), (1,3),(1,3),(2,0),(2,0),(2,0),(2,0),(2,0)};
c.int size = n>m ? n:m;
Let the input of the coordinates be an array of coordinates. coord_t c[k]
struct coord_t {
int x;
int y;
};
1. My idea is to create an array of size = n>m?n:m;
2. int array[size] = {0} ; //initialize all the elements in the array to zero
for(i=0;i<k;i++)
{
array[c[i].x] = +1;
count++;
}
int tempCount =0;
for(i=0;i<k;i++)
{
if(array[i]!=0)
{
tempCount += array[i];
}
if(tempCount >= count/2)
{
break;
}
}
int x_median = i;
//similarly with y coordinate.
int array[size] = {0} ; //initialize all the elements in the array to zero
for(i=0;i<k;i++)
{
array[c[i].y] = +1;
count++;
}
int tempCount =0;
for(i=0;i<k;i++)
{
if(array[i]!=0)
{
tempCount += array[i];
}
if(tempCount >= count/2)
{
break;
}
}
int y_median = i;
coord_t temp;
temp.x = x_median;
temp.y= y_median;
return temp;
Sample Working code for MxM matrix with k points:
*Problem
Given a MxM grid . and N people placed in random position on the grid. Find the optimal meeting point of all the people.
/
/
Answer:
Find the median of all the x coordiates of the positions of the people.
Find the median of all the y coordinates of the positions of the people.
*/
#include<stdio.h>
#include<stdlib.h>
typedef struct coord_struct {
int x;
int y;
}coord_struct;
typedef struct distance {
int count;
}distance;
coord_struct toFindTheOptimalDistance (int N, int M, coord_struct input[])
{
coord_struct z ;
z.x=0;
z.y=0;
int i,j;
distance * array_dist;
array_dist = (distance*)(malloc(sizeof(distance)*M));
for(i=0;i<M;i++)
{
array_dist[i].count =0;
}
for(i=0;i<N;i++)
{
array_dist[input[i].x].count +=1;
printf("%d and %d\n",input[i].x,array_dist[input[i].x].count);
}
j=0;
for(i=0;i<=N/2;)
{
printf("%d\n",i);
if(array_dist[j].count !=0)
i+=array_dist[j].count;
j++;
}
printf("x coordinate = %d",j-1);
int x= j-1;
for(i=0;i<M;i++)
array_dist[i].count =0;
for(i=0;i<N;i++)
{
array_dist[input[i].y].count +=1;
}
j=0;
for(i=0;i<N/2;)
{
if(array_dist[j].count !=0)
i+=array_dist[j].count;
j++;
}
int y =j-1;
printf("y coordinate = %d",j-1);
z.x=x;
z.y =y;
return z;
}
int main()
{
coord_struct input[5];
input[0].x =1;
input[0].y =2;
input[1].x =1;
input[1].y =2;
input[2].x =4;
input[2].y =1;
input[3].x = 5;
input[3].y = 2;
input[4].x = 5;
input[4].y = 2;
int size = m>n?m:n;
coord_struct x = toFindTheOptimalDistance(5,size,input);
}
Your algorithm is fine, and divide the problem into two one-dimensional problem. And the time complexity is O(nlogn).
You only need to divide every groups of people into n single people, so every move to left, right, up or down will be 1 for each people. We only need to find where's the (n + 1) / 2th people stand for row and column respectively.
Consider your sample. {(-100,0,100),(100,0,100),(0,1,1)}.
Let's take the line numbers out. It's {(-100,100),(100,100),(0,1)}, and that means 100 people stand at -100, 100 people stand at 100, and 1 people stand at 0.
Sort it by x, and it's {(-100,100),(0,1),(100,100)}. There is 201 people in total, so we only need to set the location at where the 101th people stands. It's 0, and that's for the answer.
The column number is with the same algorithm. {(0,100),(0,100),(1,1)}, and it's sorted. The 101th people is at 0, so the answer for column is also 0.
The answer is (0,0).
I can think of O(n) solution for one dimensional problem, which in turn means you can solve original problem in O(n+m+G).
Suppose, people are standing like this, a_0, a_1, ... a_n-1: a_0 people at spot 0, a_1 at spot 1. Then the solution in pseudocode is
cur_result = sum(i*a_i, i = 1..n-1)
cur_r = sum(a_i, i = 1..n-1)
cur_l = a_0
for i = 1:n-1
cur_result = cur_result - cur_r + cur_l
cur_r = cur_r - a_i
cur_l = cur_l + a_i
end
You need to find point, where cur_result is minimal.
So you need O(n) + O(m) for solving 1d problems + O(G) to build them, meaning total complexity is O(n+m+G).
Alternatively you solve 1d in O(G*log G) (or O(G) if data is sorted) using the same idea. Choose the one from expected number of groups.
you can solve this in O(G Log G) time by reducing it to, two one dimensional problems as you mentioned.
And as to how to solve it in one dimension, just sort them and go through them one by one and calculate cost moving to that point. This calculation can be done in O(1) time for each point.
You can also avoid Log(G) component if your x and y coordinates are small enough for you to use bucket/radix sort.
Inspired by kilotaras's idea. It seems that there is a O(G) solution for this problem.
Since everyone agree with the two dimensional problem can be reduced to two one dimensional problem. I will not repeat it again. I just focus on how to solve the one dimensional problem
with O(G).
Suppose, people are standing like this, a[0], a[1], ... a[n-1]. There is a[i] people standing at spot i. There are G spots having people(G <= n). Assuming these G spots are g[1], g[2], ..., g[G], where gi is in [0,...,n-1]. Without losing generality, we can also assume that g[1] < g[2] < ... < g[G].
It's not hard to prove that the optimal spot must come from these G spots. I will pass the
prove here and left it as an exercise if you guys have interest.
Since the above observation, we can just compute the cost of moving to the spot of every group and then chose the minimal one. There is an obvious O(G^2) algorithm to do this.
But using kilotaras's idea, we can do it in O(G)(no sorting).
cost[1] = sum((g[i]-g[1])*a[g[i]], i = 2,...,G) // the cost of moving to the
spot of first group. This step is O(G).
cur_r = sum(a[g[i]], i = 2,...,G) //How many people is on the right side of the
second group including the second group. This step is O(G).
cur_l = a[g[1]] //How many people is on the left side of the second group not
including the second group.
for i = 2:G
gap = g[i] - g[i-1];
cost[i] = cost[i-1] - cur_r*gap + cur_l*gap;
if i != G
cur_r = cur_r - a[g[i]];
cur_l = cur_l + a[g[i]];
end
end
The minimal of cost[i] is the answer.
Using the example 5 1 0 3 to illustrate the algorithm.
In this example,
n = 4, G = 3.
g[1] = 0, g[2] = 1, g[3] = 3.
a[0] = 5, a[1] = 1, a[2] = 0, a[3] = 3.
(1) cost[1] = 1*1+3*3 = 10, cur_r = 4, cur_l = 5.
(2) cost[2] = 10 - 4*1 + 5*1 = 11, gap = g[2] - g[1] = 1, cur_r = 4 - a[g[2]] = 3, cur_l = 6.
(3) cost[3] = 11 - 3*2 + 6*2 = 17, gap = g[3] - g[2] = 2.

suggest an algorithm for the following puzzle!

There are n petrol bunks arranged in circle. Each bunk is separated from the rest by a certain distance. You choose some mode of travel which needs 1litre of petrol to cover 1km distance. You can't infinitely draw any amount of petrol from each bunk as each bunk has some limited petrol only. But you know that the sum of litres of petrol in all the bunks is equal to the distance to be covered.
ie let P1, P2, ... Pn be n bunks arranged circularly. d1 is distance between p1 and p2, d2 is distance between p2 and p3. dn is distance between pn and p1.Now find out the bunk from where the travel can be started such that your mode of travel never runs out of fuel.
There is an O(n) algorithm.
Assume v[0] = p1 - d1, v[1] = p2 - d2, ... , v[n-1] = pn - dn. All we need to do is finding a starting point i, such that all the partial sum is no less than 0, i.e., v[i] >= 0, v[i] + v[(i+1)%n] >= 0, v[i] + v[(i+1)%n] + v[(i+2)%n] >= 0, ..., v[i]+...+v[(i+n-1)%n] >= 0.
We can find such a start point by calculating s[0] = v[0], s[1] = v[0]+v[1], s[2] = v[0]+v[1]+v[2], ..., s[n-1] = v[0] + ... + v[n-1], and pick up the minimum s[k]. Then the index (k+1)%n is the start point.
Proof: Assume the minimum element is s[k]. By the problem description, there must be the minimum s[k] <= 0.
Because the total sum v[0] + v[1] + ... + v[n-1] = 0, we have v[k+1] + v[k+2] + ... v[n-1] = -s[k] >= 0, and it is impossible that v[k+1] + ... v[j] < 0 (k < j < n). (Because if v[k+1] + ... v[j] < 0, then s[j] < s[k], which is contradictory with the assumption that s[k] is minimum.) So we have v[k+1] >= 0, v[k+1] + v[k+2] >= 0, ..., v[k+1] + v[k+2] + ... + v[n-1] >= 0.
Because s[k] is the minimum one, We also have v[k+1] + v[k+2] + ... + v[n-1] + v[0] = -s[k] + v[0] = -s[k] + s[0] >= 0, -s[k] + v[0] + v[1] = -s[k] + s[1] >= 0, ..., -s[k] + v[0] + v[1] + ... + v[k-1] = -s[k] + s[k-1] >= 0. So all the parital sum starting from (k+1) is no less than 0. QED.
Let's choose a junk algorithm that we know is wrong to see why it is wrong...
Notation...
Current Point: (gallons of gas at Current Point, gallons required to make next point)-> Remaining Gas (gallons)
In a little more mathematical form:
P[i]: (g(P[i]), d(P[i+1])) -> sum of (g(P[i]) - d(P[i+1])) from i=1 to current point-1
(And now for the bad algorithm...)
P1: (2,2) -> 0 (at P2)
P2: (5,3) -> 2 (at P3)
P3: (2,4) -> 0 (at P4)
P4: (2,5) -> -3 (ran out of gas 3 miles short of P5)
In order to make it to P5, we have to have three extra gallons of gas by the time we make it to P3, and in order to have 3 extra gallons at P3, we need to have 3 extra gallons at P1:
??? -> +3 (at P1)
P1: (2,2) -> 0+3 = 3 (at P2)
P2: (5,3) -> 2+3 = 5 (at P3)
P3: (2,4) -> 0+3 = 3 (at P4)
P4: (2,5) -> -3 +3 = 0 (made it to P5)
The trick, therefore, is to find the very worst sections -- where you are not given enough gas to traverse them. We know we can't start from P4, P3, P2, or P1. We have to start somewhere earlier and save up enough gas to make it through the bad section.
There will no doubt be multiple bad sections within the circle, making this somewhat complicated, but it's actually quite easy to figure out how to do this.
It's possible that the next few points following the very worst stretch in the circle could be traveled after the stretch, but only if they make no changes to your gas reserves. (e.g. the point after the worst stretch gives you 2 gallons of gas and makes you go 2 gallons of distance to the next point.)
In some cases, however, the worst section MUST be covered last. That's because before you start on that section, you need as much gas saved up as possible, and the next point after the worst stretch might give you the very last bit of gas that you need, which means you need to traverse it prior to taking on the worst stretch. Although there may exist multiple solutions, the simple fact of the matter is that traversing the worst section last is ALWAYS a solution. Here's some code:
class point_ {
int gasGiven_;
int distanceToNextPoint_;
public:
int gasGiven() {return gasGiven_;}
int distanceToNextPoint {return distanceToNextPoint_;}
}
class Circle_ {
public:
numberOfPoints;
point_ *P;
}
In main():
int indexWorstSection=0;
int numberPointsWorstSection=0;
int worstSum=0;
int currentSum=0;
int i=0;
int startingPoint =0;
// construct the circle, set *P to malloc of numberOfPoints point_'s, fill in all data
while (i<(Circle.numberOfPoints-1) || currentSum<0)
{
currentSum += Circle.P[i].gasGiven() - Circle.P[i].distanceToNextPoint();
if (currentSum < worstSum) { worstSum = currentSum; indexWorstSection=i-numberPointsWorstSection; startingPoint=i;}
if (currentSum>0) { currentSum=0; }
else { numberPointsWorstSection++; }
if (i==(Circle.numberOfPoints-1)) { i=0; }
else { i++; }
}
if (indexWorstSection<0) indexWorstSection=Circle.numberOfPoints+indexWorstSection;
The reason why you can't make it a for-loop is because the worst section might be, for example, from i=(Circle.numberOfPoints -2) to i=3. If the currentSum is under zero, it must continue back at the start of the array.
Haven't tried the code and haven't done any serious programming in almost a decade. Sorry if it has some bugs. You will no doubt have to clean this up a bit.
This does what several of the other answers do - finds the minimum of the "graph" created by the net-change-in-petrol deltas as you circle around. Depending on where we start, the exact values may be moved uniformly upwards or downwards compared to some other starting position, but the index of the minimal value is always a meaningful indication of where we can start and know we'll never run out of petrol. This implementation tries to minimise memory use and completes in O(n).
#include <iostream>
int dist[] = { 3, 10, 2, 4, 6, 9 };
int refill[] = { 3, 4, 6, 3, 7, 11 };
static const int n = sizeof dist / sizeof *dist;
int main()
{
int cum = 0, min = 0, min_index = 0;
for (int i = 0; i < n; ++i)
{
cum += refill[i] - dist[i];
std::cout << cum << ' ';
if (cum <= min)
{
min = cum;
min_index = i;
}
}
std::cout << "\nstart from index " << (min_index + 1) % n << " (0-based)\n";
}
See it running on ideone.com
Here's an approach that works in O(n) time and O(1) space. Start at any station, call it station 0, and advance until you run out of gas. If you don't run out of gas, done. Otherwise, if you run out between stations k and k+1, start over again at station k+1. Make a note if you pass 0 again, and if you run out after that it can't be done.
The reason this works is because if you start at station i and run out of gas between stations k and k+1, then you will also run out of gas before station k+1 if you start at any station between i and k.
Here's an algorithm, given an arrays P (petrol) and D (distance):
int position = 0;
int petrol = P[0];
int distance = D[0];
int start = 0;
while (start < n) {
while (petrol >= distance) {
petrol += P[++position % N] - distance;
distance = D[position % N];
if (position % N == start)
return start;
}
start = position;
petrol = P[start];
}
return -1;
Each leg of the trip has a net effect on fuel, adding from storage and using to make the trip. All you need to do is loop through once, keeping track of your fuel level when you arrive at each point, even if it is negative. Keep track of the lowest fuel level and which point it occurred on. If you start at that point, you will be able to make it around from there without running out of fuel. This assumes that you start with an empty tank and only get gas from the place you are starting, also that you can always take all the gas, you won't ever get full and have to leave gas behind.
Let's say you have 5 points, P1 to P5:
Point Fuel Distance to next point
P1 5 8
P2 3 4
P3 12 7
P4 1 4
P5 7 5
If you choose P1, then load up on 5 fuel, travelling to P2 leaves you with -3 fuel. Going on you get these numbers:
Point Fuel Balance (before refueling)
P1 0
P2 -3
P3 -4
P4 1
P5 -2
P1 0
So if you start at the lowest value, P3, you can make it back around (fuel 0 to start, 5 at P4, 2 at P5, 4 at P1, 1 at P2, 0 back at P3)
float [] storedFuel = { 1, 1, 1, 1, 1, 1 };
float [] distance = { 1, 1, 1, 1, 1, 1 };
int n = 6;
int FindMinimumPosition()
{
float fuel = 1;
int position = 0;
float minimumFuel = 1;
int minimumPosition = 0;
while (position < n)
{
fuel += storedFuel[position];
fuel -= distance[position];
position++; // could be n which is past array bounds
if (fuel < minimumFuel) {
minimumFuel = fuel;
minimumPosition = position % n;
}
}
return minimumPosition
}
Off the top of my head, here's an algorithm that should work:
let e1 = (the amount of petrol in P1) - d1 (i.e., the excess petrol in P1 over what is needed to travel to P2), and similarly for e2, ..., en. (These numbers can be positive or negative.)
Form the partial sums s1 = e1; s2 = e1 + e2; ..., sn = e1 + e2 + ... + en. We know from the conditions of the problem that sn = 0.
The problem now is to find a circular permutation of the bunks (or, more simply, of the e values) so that none of the s values are negative. One can simply repeatedly shift one, updating the s values, until a solution is found. (It's not immediately obvious that there is always a solution, but I think there is. If you shift n times without finding a solution, then you're guaranteed that there is none.)
This is an O(n^2) algorithm--not very good. A good heuristic (possibly an exact solution) may be to shift so that the largest-magnitude negative s value is shifted to position n.
For each gap, find the profit or loss earned by filling up at the bunk before the gap, and then crossing the gap. At an arbitrary point work out total amount of petrol remaining at each point of a complete circle, accepting that it may be negative at some point.
Now repeatedly circularly shift that solution. Remove the information for the last point, which will now be the first point. Set up an offset to take account of the fact that you are now starting one point further back, and will more (or less) petrol at each remaining point. Add in information for the new point, taking account of the offset. This solution is feasible if the minimum amount of petrol at any point, plus the offset, is greater than zero.
You can use some sort of log n data structure (sorted map, priority queue...) to keep track of the minimum so this takes the cost down to n log n.
Here is an O(n) solution
private int findStartingPoint(int[] petrol, int[] dist, int[] mileage){
int curPoint = 0;
boolean done = false;
while(curPoint < petrol.length && !done)
{
int prevPoint = curPoint;
int nextPoint = (curPoint+1) % petrol.length;
int nextSolutionPoint = curPoint + 1;
int totalPetrol = 0;
while(nextPoint != curPoint){
totalPetrol += petrol[prevPoint] - (dist[prevPoint]/mileage[prevPoint]);
if(totalPetrol < 0){
curPoint = nextSolutionPoint;
break;
}
prevPoint = nextPoint;
nextPoint = (nextPoint + 1) % petrol.length;
nextSolutionPoint++;
}
if(curPoint == nextPoint){
return curPoint;
}
}
return -1;
}
}

Resources