Need to arrange sequence of events - algorithm

I was asked this question in an coding interview I tried hashmap, heap tree, and queue but nothing worked. I want to understand what I missed, can someone tell me how to approach this problem.
DESCRIPTION It's the year 2050. Teleportation has been made possible since 2045. Now you have just bought a teleportation machine for yourself. However. operating the machine is not a child's play. Before you can teleport to some other places. you need to do some arrangements on the machine. There are N equipments in the machine which are needed to be switched on and there are M types of dependencies between various equipment. Now you need to figure out the order in which you should switch on the equipment so as to make the machine start.
Input
• First-line will contain 2 numbers:
N representing number of equipment in the machine.
M representing number of equipment dependencies.
• Next M lines contain 2 integers A and B representing a dependency from A to B (That means A must be switched on to start B.
Output
• On a single line, print the order(separated by space) in which the machines should be switched on to do teleportation.
Constraints
• 1 <= N <= 500
• 1 <= M = N(N-1)/2
• 1 <= A <= 500
• 1 < B <= 500
Sample Test Case
Solution Input:
6 6
1 2
1 3
2 5
3 4
5 6
4 6
Sample Output
1 3 4 2 5 6
Explanation
If you follow the pattern. you will observe that to switch on equipment 6. you would need to switch on 4 and 5. To switch on equipment 4 and 5. we need to switch on equipment 3 and 2 respectively. Finally to switch on equipment 3 and 2 we need to switch on equipment 1.

It's a classic problem called topological sort.
Count the number of machines needed to turn on to start each machine.
With your case:
cnt[1] = 0
cnt[2] = 1 // machine 1
cnt[3] = 1 // machine 1
cnt[4] = 1 // machine 3
cnt[5] = 1 // machine 2
cnt[6] = 2 // machine 4, 5
If cnt equal to 0, it means this machine can be turn on.
Something like this should work:
queue<int> q;
for (int i = 1; i <= n; i++)
if (cnt[i] == 0) q.push(i);
while (!q.empty()) {
int id = q.front(); q.pop(); // Turn on machine id
print (id)
for (int i = 0; i < dep[id].size(); i++) { // Dependencies for machine id
cnt[dep[id][i]]--;
if (cnt[dep[id][i]] == 0)
q.push(dep[id][i]);
}
}

The problem can be rephrased to:
Input: an unweighted, directed acyclic graph G(V, E)
Output: a topological ordering of G.
Possible Algorithm
The process needed is called Topological Sorting. This reference lists a few alternative algorithms.
One way is to use a depth-first search and mark nodes as visited as you encounter them. Do not visit those again. When backtracking from recursion, prepend the current node to the output list. This will ensure that all dependent nodes have already been add to that list, and this "ancestor" precedes them all.

Related

Optimal choice algorithm

i have an appointment for university which is due today and i start getting nervous. We recently discussed dynamic programming for algorithm optimization and now we shall implement an algorithm ourself which uses dynamic programming.
Task
So we have a simple game for which we shall write an algorithm to find the best possible strategy to get the best possible score (assuming both players play optimized).
We have a row of numbers like 4 7 2 3 (note that according to the task description it is not asured that it always is an equal count of numbers). Now each player turnwise takes a number from the back or the front. When the last number is picked the numbers are summed up for each player and the resulting scores for each player are substracted from each other. The result is then the score for player 1. So an optimal order for the above numbers would be
P1: 3 -> p2: 4 -> p1: 7 -> p2: 2
So p1 would have 3, 7 and p2 would have 4, 2 which results in a final score of (3 + 7) - (4 + 2) = 4 for player 1.
In the first task we should simply implement "an easy recursive way of solving this" where i just used a minimax algorithm which seemed to be fine for the automated test. In the second task however i am stuck since we shall now work with dynamic programming techniques. The only hint i found was that in the task itself a matrix is mentioned.
What i know so far
We had an example of a word converting problem where such a matrix was used it was called Edit distance of two words which means how many changes (Insertions, Deletions, Substitutions) of letters does it take to change one word into another. There the two words where ordered as a table or matrix and for each combination of the word the distance would be calculated.
Example:
W H A T
| D | I
v v
W A N T
editing distance would be 2. And you had a table where each editing distance for each substring was displayed like this:
"" W H A T
1 2 3 4
W 1 0 1 2 3
A 2 1 1 2 3
N 3 2 2 2 3
T 4 3 3 3 2
So for example from WHA to WAN would take 2 edits: insert N and delete H, from WH to WAN would also take 2 edits: substitude H->A and insert N and so on. These values where calculated with an "OPT" function which i think stands for optimization.
I also leanred about bottom-up and top-down recursive schemes but im not quite sure how to attach that to my problem.
What i thought about
As a reminder i use the numbers 4 7 2 3.
i learned from the above that i should try to create a table where each possible result is displayed (like minimax just that it will be saved before). I then created a simple table where i tried to include the possible draws which can be made like this (which i think is my OPT function):
4 7 2 3
------------------
a. 4 | 0 -3 2 1
|
b. 7 | 3 0 5 4
|
c. 2 | -2 -5 0 -1
|
d. 3 | -1 -4 1 0
the left column marks player 1 draws, the upper row marks player 2 draws and each number then stands for numberP1 - numberP2. From this table i can at least read the above mentioned optimal strategy of 3 -> 4 -> 7 -> 2 (-1 + 5) so im sure that the table should contain all possible results, but im not quite sure now how to draw the results from it. I had the idea to start iterating over the rows and pick the one with the highest number in it and mark that as the pick from p1 (but that would be greedy anyways). p2 would then search this row for the lowest number and pick that specific entry which would then be the turn.
Example:
p1 picks row a. 7 | 3 0 5 4 since 5 is the highest value in the table. P2 now picks the 3 from that row because it is the lowest (the 0 is an invalid draw since it is the same number and you cant pick that twice) so the first turn would be 7 -> 4 but then i noticed that this draw is not possible since the 7 is not accessible from the start. So for each turn you have only 4 possibilities: the outer numbers of the table and the ones which are directly after/before them since these would be accessable after drawing. So for the first turn i only have rows a. or d. and from that p1 could pick:
4 which leaves p2 with 7 or 3. Or p1 takes 3 which leaves p2 with 4 or 2
But i dont really know how to draw a conclusion out of that and im really stuck.
So i would really like to know if im on the right way with that or if im overthinking this pretty much. Is this the right way to solve this?
The first thing you should try to write down, when starting a dynamic programming algorithm, is a recurrence relation.
Let's first simplify a very little the problem. We will consider that the number of cards is even, and that we want to design an optimal strategy for the first player to play. Once we have managed to solve this version of the problem, the others (odd number of cards, optimize strategy for second player) follows trivially.
So, first, a recurrence relation. Let X(i, j) be the best possible score that player 1 can expect (when player 2 plays optimally as well), when the cards remaining are from the i^th to the j^th ones. Then, the best score that player 1 can expect when playing the game will be represented by X(1, n).
We have:
X(i, j) = max(Arr[i] + X(i+1, j), X(i, j-1) + Arr[j]) if j-i % 2 == 1, meaning that the best score that player one can expect is the best between taking the card on the left, and taking the card on the right.
In the other case, the other player is playing, so he'll try to minimize:
X(i, j) = min(Arr[i] + X(i+1, j), X(i, j-1) + Arr[j]) if j-i % 2 == 0.
The terminal case is trivial: X(i, i) = Arr[i], meaning that when there is only one card, we just pick it, and that's all.
Now the algorithm without dynamic programming, here we only write the recurrence relation as a recursive algorithm:
function get_value(Arr, i, j) {
if i == j {
return Arr[i]
} else if j - i % 2 == 0 {
return max(
Arr[i] + get_value(i+1, j),
get_value(i, j-1) + Arr[j]
)
} else {
return min(
Arr[i] + get_value(i+1, j),
get_value(i, j-1) + Arr[j]
)
}
}
The problem with this function is that for some given i, j, there will be many redundant calculations of X(i, j). The essence of dynamic programming is to store intermediate results in order to prevent redundant calculations.
Algo with dynamic programming (X is initialized with + inf everywhere.
function get_value(Arr, X, i, j) {
if X[i][j] != +inf {
return X[i][j]
} else if i == j {
result = Arr[i]
} else if j - i % 2 == 0 {
result = max(
Arr[i] + get_value(i+1, j),
get_value(i, j-1) + Arr[j]
)
} else {
result = min(
Arr[i] + get_value(i+1, j),
get_value(i, j-1) + Arr[j]
)
}
X[i][j] = result
return result
}
As you can see the only difference with the algorithm above is that we now use a 2D array X to store intermediate results. The consequence on time complexity is huge, since the first algorithm runs in O(2^n), while the second runs in O(n²).
Dynamic programming problems can generally be solved in 2 ways, top down and bottom up.
Bottom up requires building a data structure from the simplest to the most complex case. This is harder to write, but offers the option of throwing away parts of the data that you know you won't need again. Top down requires writing a recursive function, and then memoizing. So bottom up can be more efficient, top down is usually easier to write.
I will show both. The naive approach can be:
def best_game(numbers):
if 0 == len(numbers):
return 0
else:
score_l = numbers[0] - best_game(numbers[1:])
score_r = numbers[-1] - best_game(numbers[0:-1])
return max(score_l, score_r)
But we're passing a lot of redundant data. So let's reorganize it slightly.
def best_game(numbers):
def _best_game(i, j):
if j <= i:
return 0
else:
score_l = numbers[i] - _best_game(i+1, j)
score_r = numbers[j-1] - _best_game(i, j-1)
return max(score_l, score_r)
return _best_game(0, len(numbers))
And now we can add a caching layer to memoize it:
def best_game(numbers):
seen = {}
def _best_game(i, j):
if j <= i:
return 0
elif (i, j) not in seen:
score_l = numbers[i] - _best_game(i+1, j)
score_r = numbers[j-1] - _best_game(i, j-1)
seen[(i, j)] = max(score_l, score_r)
return seen[(i, j)]
return _best_game(0, len(numbers))
This approach will be memory and time O(n^2).
Now bottom up.
def best_game(numbers):
# We start with scores for each 0 length game
# before, after, and between every pair of numbers.
# There are len(numbers)+1 of these, and all scores
# are 0.
scores = [0] * (len(numbers) + 1)
for i in range(len(numbers)):
# We will compute scores for all games of length i+1.
new_scores = []
for j in range(len(numbers) - i):
score_l = numbers[j] - scores[j+1]
score_r = numbers[j+i] - scores[j]
new_scores.append(max(score_l, score_r))
# And now we replace scores by new_scores.
scores = new_scores
return scores[0]
This is again O(n^2) time but only O(n) space. Because after I compute the games of length 1 I can throw away the games of length 0. Of length 2, I can throw away the games of length 1. And so on.

Run time Error on URI Online Judge

I am trying the following problem on URI OJ
After buying many adjacent farms at the west region of Santa Catarina, the Star family built a single road which passes by all farms in sequence. The first farm of the sequence was named Star 1, the second Star 2, and so on. However, the brother who lives in Star 1 has got mad and decided to make a Star Trek in order to steal sheep from the proprieties of his siblings. But he is definitely crazy. When passes by the farm Star i, he steals only one sheep (if there is any) from that farm and moves on either to Star i + 1 or Star i - 1, depending on whether the number of sheep in Star i was, respectively, odd or even. If there is not the Star to which he wants to go, he halts his trek. The mad brother starts his Star Trek in Star 1, stealing a sheep from his own farm.
INPUT
The first input line consists of a single integer N (1 ≤ N ≤ 106), which represents the number of Stars. The second input line consists of N integers, such that the ith integer, Xi (1 ≤ Xi ≤ 10^6), represents the initial number of sheep in Star i.
OUTPUT
Output a line containing two integers, so that the first represents the number of Stars attacked by the mad brother and the second represents the total number of non-stolen sheep.
I tried to solve the following problem using Brute Force. But every time I submit, I am receiving a Command terminated by signal (11: SIGSEGV). As I searched this error occurs when we are trying to access a memory segment that does not exist, so what can I do to improve my code, and where is the error actually occurring. I tried looking up and came up with the fact the we can have a python list of size 536870912 safely, so I am guessing 10^6 being much smaller than this is also safe.
n = int(raw_input())
x = map(int, raw_input().split())
total, i, stolen, visited = sum(x), 0, 0, set()
while i in range(n) and x[i]:
visited.add(i)
stolen += 1
x[i] -= 1
if (x[i] + 1) % 2 == 1:
i += 1
else:
i -= 1
print(str(len(visited)) + ' ' + str(total - stolen))
Max Size of Python List
Here are sample runs of my program
INPUT
8
1 3 5 7 11 13 17 19
EXPECTED OUTPUT
8 68
OUTPUT
8 68
INPUT
8
1 3 5 7 11 13 16 19
EXPECTED OUTPUT
7 63
OUTPUT
7 63
I don't know Python so I cannot help finding the bug, but I think your algorithm is buggy.
The problem says:
If there is not the Star to which he wants to go, he halts his trek.
However it seems that your algorithm also stops if there is no sheep left on a farm.
Anyway the problem looks quite simple in the form as you inserted so I think that the range of the first parameter is NOT
(1 ≤ N ≤ 106)
but rather
(1 ≤ N ≤ 106)
In this case the size of the list could be a problem... especially if they limit the available memory for the code.
But actually you don't need to store all the input parameters! You can calculate the stolen sheep quite easily on the fly:
You start from the first farm.
2.1. If there are even number of sheep here then none of the following farms will be visited and 1 sheep will be stolen from here.
2.2. If there are odd number of sheep here then 1 sheep will be stolen right now, and 1 more when the mad star comes back (At that time there will be even number of sheep here and also in all of the previous farms so the mad start won't visit it any more.) We also have to handle the case when there is only one sheep at the farm because in this case only 1 sheep can be stolen here.
Handle the next farm
At the end you have to handle one more special case: If there were even number of sheep in each of the farms then exactly 1 sheep was stolen from each farm, because in this case the mad star never turns back. (And there is at least one sheep in each farm)
Here is a simple algorithm as a pseudo code:
int N= read();
boolean visit = true;
int visited = 0;
int total = 0;
int stolen = 0;
while(--N >0 ) {
int x = read();
total+=x;
if(visit) {
visited++;
if(x%2 == 1) {
stolen+=min(x,2);
} else {
stolen+=1;
visit = false;
}
}
}
if(visit) {
print(N + ' ' = (total-N));
} else {
print(visited + ' ' + (total-stolen));
}

Minimum time to shift given weight boxes from one position to other when capacity of machines are given

Given n boxes of different weights and m machines of different weight carrying capacity. Find the minimum time required to move all boxes.
Machines Capacities : C[0] , C[1] , C[2],........C[m-1].
Box Weights : W[0] , W[1] , W[2] .... W[n].
Each machine takes 1 minute to carry one time.
What can be the optimal approach recursive approach will be to try assigning current box to given machine and not assign and recur for rest of thee boxes.
Note: A single machine can carry boxes multiple times , Each round trip takes exactly 1 unit time.
Sort the machines in descending order of weight carrying capacities.
Sort the boxes in increasing order of weights.
Now, add boxes one by one to each machine until the weight carrying capacity of the machine exceeds.
When it exceeds then move to the next machine.
Pseudocode:
W[] //sorted in increasing order
C[] //sorted in decreasing order
i = 0 //pointer for box
j = 0 //pointer for machine
curr_weight = 0
time_taken = 0
while i<n:
curr_weight = curr_weight + W[i]
if curr_weight > C[j]:
curr_weight = 0
j = j + 1
time_taken = time_taken + 1
else
i = i + 1
end while
print time_taken + 1
Check for boundary cases. For example if j exceeds m-1
Edit: In case the same machine can carry multiple times
Maintain a sorted STACK for machines [sorted in descending order]. As soon as a machine gets full and leaves for transportation, pop the machine from STACK and enqueue it in a QUEUE. As soon as a machine is ready to carry again(after it has returned from the transportation job), dequeue it from the QUEUE and push it back on the STACK.
Assumption: time to move from source to destination for a machine is 1 minute. time to move back from destination to source for a machine is 1 minute.

Shortest Distance from Leaf to Root of a Directed tree

Here is a very interesting problem which I have encountered: there is a directed tree in which the weight of each node changes with time and I have to find the distance from the root to some node.
Problem Statement:
There’s a long queue in front of a ticket counter. Here are the queue
considerations.
There can be max 2 incoming queues merging at a junction point
There can be only one outgoing queue from any junction point
There can be multiple junction points & the queues move
uni-directionally
There will be only one final ticket counter point to which all the
queues lead
There are multiple entry points for the fans to reach the
counter
I need to design a system that can suggest to the fans the
“Optimal Path” and its “Expected Time" to reach the counter
The expected time to reach the counter from a queue depends on the number of people in that queue plus the number of people in the other queues.
Time taken to cross the ticket counter and receive the ticket is 1
time unit
Assume that there is a policeman standing at each junction point
whose job is to open the junction gate to send people from the
in-queue(s) to the out-queue . If there are multiple in-queues for a
junction, the policeman will send fans from each queue one by one
alternatively
For example, if there are 2 in-queues containing 3 fans each, the leading person from queue1 will be sent in first, followed by the leading person from queue2, followed by next person from queue1 and so on. It’s an alternate pick between the incoming queues.
Full Problem Statement
For a Given Input
The first line contains the number of junctions
The second line contains the number of queues
The next 'e' lines contain three values: the start junction, the end
junction and the number of people on this queue. (This is also the maximum number of people that can stand in this queue.)
Calculate the minimum time for a person to reach the ticket counter who is just about to enter any queue. Also, output the path that he should take to reach the counter in minimum time in the worst case (at each junction point, the policeman starts choosing people from the in-queue other than the one we are calculating the minimum time for).
How can one solve this type of time-varying problem?
For Example:
7
6
1 5 9
2 5 5
3 6 1
4 6 3
5 7 7
6 7 4
Graph Looks Like This:
Ticket counter point: 7
Entry points: 1, 2, 3, 4
Time required for a person who is just entering the queue from entry
point 3: 1 person from queue(3,6) + 2 people from queue(4,6) + 4
people from queue(6,7) + 7 people from queue(5,7) + 1 person from
queue(1,5) will go before this person.
Optimal time = 15
Path is 3 -> 6 -> 7
This problem can be solved by finding the shortest path from each entry node (leaves) to the exit node (root).
In my implementation below I used an adjacency matrix to represent that kind of (directed) graph, but you can think of it as a binary tree (because the problem defined maximum 2 input queues for each junction).
Pseudo-code
int shortestPath(root)
if (both childs exists)
return min(shortestPath(node->left),shortestPath(node->right))*2+1
if (left child exists)
return shortestPath(node->left)
if (right child exists)
return shortestPath(node->right)
return 0; //no childs
The only difference between a normal shortest path and this problem is that whenever we have two incoming queues, the policeman sends fans from each queue one by one alternatively. Which means that in order to pass that queue it will take double the time +1. The +1 is because we assume that he starts from the longer queue path.
C++ Code
Here is a working C++ code that returns a pair with both the optimal time and its path. In case there are more than one optimal paths it will return only one of them.
const pair<int,vector<int>>& min(const pair<int,vector<int>>& a, const pair<int,vector<int>>& b) {
return (a.first < b.first) ? a : b;
}
pair<int,vector<int>> findShortestPath(vector<vector<int>>& graph, int v){
vector<pair<int,vector<int>>> childs;
for (int i=0; i<v; i++){
if (graph[i][v] != -1){
pair<int,vector<int>> path = findShortestPath(graph,i);
path.second.push_back(v+1);
childs.push_back(make_pair(path.first + graph[i][v], path.second));
}
}
if (childs.size() == 2){
pair<int,vector<int>> path = min(childs[0],childs[1]);
return make_pair(path.first*2+1, path.second);
}
if (childs.size() == 1){
return make_pair(childs[0].first,childs[0].second);
}
else{
vector<int> start = {v+1};
return make_pair(0,start);
}
}
The time complexity of this code is O(n^2) where n is the number of vertices. You might also be able to implement it in O(n) using adjacency list representation (= binary tree).
For completeness, here is also the main for creating the graph from the given input and printing the optimal time and path. See this live test of your example's input
int main()
{
int n, e;
cin >> n; //num of vertices
cin >> e; //num of queues
vector<vector<int>> graph;
//initialize graph matrix cells to -1
graph.resize(n);
for (int i=0;i<n;i++){
graph[i].resize(n);
for (int j=0;j<n;j++)
graph[i][j] = -1;
}
//add edges and their weights
for (int i=0;i<e;i++){
int s,d,val;
cin >> s >> d >> val;
graph[s-1][d-1] = val;
}
//run algorithm
pair<int,vector<int>> path = findShortestPath(graph, n-1);
//print results
cout << path.first << endl;
for (int i=0;i<path.second.size()-1;i++)
cout << path.second[i] << " -> ";
cout << path.second[path.second.size()-1] << endl;
return 0;
}
This should be solved by dynamic programming.
Let P(j) be the position of the person ,if it takes the optimal fan , to pass through the junction point j. For example P(6) = 4 in your case , because someone arriving at junction point 3 will be the 4th to pass through junction point 6 (after P27,P26 and P28).
The following three propositions are obvious and solve the problem.
If a "junction point" j is a fan , P(j) = 1 (base case)
If a "junction point" j is a proper junction point with children l and r , and there are x people in the queue between l and j and y people in the queue between r and j , we have P(j) = 2 * min( P(l) + x , P(r) + y)
If someone if the n'th to go through the counter, it takes n-1 time to get there.
You can get the time easily using DP and with some book keeping(if the min is achieved n the left or on the right) you can get which is the optimal fan.

Interviewstreet- Permutation Game

Alice and Bob play the following game:
1) They choose a permutation of the first N numbers to begin with.
2) They play alternately and Alice plays first.
3) In a turn, they can remove any one remaining number from the permutation.
4) The game ends when the remaining numbers form an increasing sequence. The person who played the last turn (after which the sequence becomes increasing) wins the game.
Assuming both play optimally, who wins the game?
Input:
The first line contains the number of test cases T. T test cases follow. Each case contains an integer N on the first line, followed by a permutation of the integers 1..N on the second line.
Output:
Output T lines, one for each test case, containing "Alice" if Alice wins the game and "Bob" otherwise.
Sample Input:
2
3
1 3 2
5
5 3 2 1 4
Sample Output:
Alice
Bob
Constraints:
1 <= T <= 100
2 <= N <= 15
The permutation will not be an increasing sequence initially.
I am trying to solve above problem. I have derived till far but I am stuck at a point. Please help me to proceed further.
In above problem, for permutation of length 2, player 1 always wins.
For a permutation of length 3, player 2 wins if the string is strictly increasing or decreasing.
For a permutation of length 4, If player 1 is able to make the string strictly increasing or decreasing by removing a character, she wins else player 2 wins.
Hence a conclusion is:
If current player is able to make the string strictly increasing he/she wins. (Trivial case)
If he/she is able to make it strictly decreasing the the winner is decided by the number of elements in that sequence. If there are even number of elements in that sequence, current player looses, else wins.
But what should be done if the resultant string is neither increasing nor decreasing??
This is a typical game problem. You have 2^15 possible positions which denote which are the remaining numbers. From the number of the remaining numbers you can derive whose turn it is. So now you have a graph that is defined in the following manner - the vertices are the possible sets of remaining numbers and there is an edge connecting two vertices u and v iff there is a move that changes set u to set v(i.e. set v has exactly one number less).
Now you already pointed out for which positions you know who is the winner straight away - the ones that represent increasing sequences of numbers this positions are marked as loosing. For all other positions you determine if they are wining or loosing in the following manner: a position is winning iff there is an edge connecting it to a loosing position. So all that is left is to something like a dfs with memoization and you can determine which positions are winning and which are loosing. As the graph is relatively small (2^15 vertices) this solution should be fast enough.
Hope this helps.
Of course, this can be done with "brute force" for small N, but don't you suspect an easier answer around inversions and the sign of a permutation?
Originally I suspected an answer like "Alice wins iff the sign is -1, else loses", but this is not the case.
But I would like to propose a representation of the problem that not only your algorithm may use, but one that will equally boost your paper-and-pen performance in this game.
An inversion is a pair of indices i<j such that a[i]>a[j]. Consider (i,j) an edge of an undirected graph with vertices 1,...,N. Each player deletes a vertex from this graph and wins if there are no edges left.
For 5 3 2 1 4, the resulting graph is
5--3
/|\ |
/ | \|
4 1--2
and Alice quickly sees that removing "5" gives Bob the opportunity to remove 2. Then no inversions are left, and Bob wins.
This game can be solved recursively.
Each time alice takes her first pick and picks i, subtract 1 from all the remaining numbers that are larger than i. Now we have the same game but with the numbers 1 to N-1
lets say your sequence is
1,3,5,4,2
on her first move, Alice can pick any number.
case1:
she picks 1, alice can win if bob cant win with 3,5,4,2 (equivalently 2,4,3,1)
case2:
she picks 3 first. Alice can win if bob cant win with 1,5,4,2 (equivalently 1,4,3,2)
case3:
she picks 5 first. Alice can win if bob cant win with 1,3,4,2
you get the idea.
So you can make a recursive function to work out the solution for a size N permutation all by using size N-1 permutations for each possible first guess. the base case for the recursion is when you have an in-order sequence.
Each step of the recursion, the person tries all possibilities and picks any that makes them win.
Because there are many combinations of moves that can get down to the same sequence, the recursion has overlapping sub problems. This means we can use dynamic programming, or simply "memoize" our function, greatly increasing efficiency.
For further speedup one may use symmetry in the permutations, as many groups of permutations are equivalent, such as the reverse of one permutation would yield the same result.
Good luck.
#tiwo ,#rup COnsidering 5 3 2 1 4 is the sequence first alice removes 5 and the bob removes 2 then the sequence is 3 1 4 which is not in increasing order then alice gets the chance to remove 1 and the the sequence is in ascending order Alice should be the answer. In the graph you gave there should be an edge between 3 and 1 as 1 and 3 are in inversion.
Please tell me where i am wrong as the answer given in the problem is infact BOB
You can solve it with minimax algorithm. Here is the code in java
import java.io.*;
import java.util.*;
import java.text.*;
import java.math.*;
import java.util.regex.*;
public class Solution {
public static Scanner sc = new Scanner(System.in);
public static void main(String[] args) {
int t = ni();
for(int i=0; i<t; i++){
int n = ni();
Map<Long, Boolean> map = new HashMap<Long, Boolean>();
int[] numbers = new int[n];
for(int j=0; j<n; j++){
numbers[j] = ni();
}
if(aliceWin(numbers, map)) System.out.println("Alice");
else System.out.println("Bob");
}
}
public static boolean aliceWin(int[] a, Map<Long, Boolean> map){
long h = hashCode(a); int temp;
if(map.containsKey(h)) return true;
for(int i=0; i<a.length; i++){
if(a[i]>0){
temp = a[i] ;
a[i] = 0;
if(isIncreasing(a)){
map.put(h, true);
a[i] = temp;
return true;
}
if(!aliceWin(a, map)) {
map.put(h, true);
a[i] = temp;
return true;
}
a[i] = temp;
}
}
return false;
}
public static long hashCode(int[] a){
long result = 0;
for(int i=0; i<a.length; i++){
result = (result << 4) + a[i];
}
return result;
}
public static boolean isIncreasing(int[] a){
int last = 0;
for(int i=0; i<a.length; i++){
if (a[i] > 0){
if(last > a[i]) return false;
last = a[i];
}
}
return true;
}
public static int ni(){
return sc.nextInt();
}
public static void print(Object... args){
System.out.println(Arrays.deepToString(args));
}
}
From blog: hackerrank-permutation-game
Here is some code that builds the graph for you, but requires you to call reverse() on the graph, create a source node connecting to all nodes in the base, flow back to source seeing if there is a way alice wins.
input_ = """2
3
1 3 2
5
5 3 2 1 4""".splitlines()
perms = [map(int,perm.split()) for perm in input_ if len(perm)>1]
"[['1', '3', '2'], ['5', '3', '2', '1', '4']]"
if networkx is None:
import networkx
from itertools import combinations
def build_graph(perm):
base = set()
G = networkx.DiGraph()
for r in range(1,len(perm)+1):
for combo in combinations(perm,r):
combo = list(combo)
if combo == sorted(combo):
base.add(tuple(combo))
continue
for i in range(r):
G.add_edge(tuple(combo),tuple(combo[:i]+combo[i+1:])) #you may want to reverse the graph later to point from base to source.
return G,base
def solve(G,base):
#dfs,
pass
for perm in perms:
G,base = build_graph(perms[0])
print solve(G,base)
can't we just check at each step that..
does a single change by the next player makes the sequence sorted.. if yes then make some other move..
or carry on with the move
like
5 3 2 1 4
if alice does 3 2 1 4
bob cannot win in a single turn by eliminating any...
like if
he does 2 1 4 it is nt sorted..
he does 3 1 4 it is nt sorted..
he does 3 2 4 it is nt sorted..
so 5 3 2 1 4 -> 3 2 1 4 is a valid move!!
now is bob's turn..
he'll check the same..
but in some time..there won't be a number such that u can make a move as above..
so u'll have to make a random move and who will win then can be easily calculated by the number of steps tht will make the sequence into single element!!
To me (using almost your own words):
If he/she is able to make it strictly increasing on the first move he/she wins (Trivial case) otherwise the the winner is decided by the number of elements in that sequence.
Take your second case as example.
I think that the graph solution is fine but it forgets that the players play in a optimal way. So don't need to check all the different path since some of them will derive from a non-optimal choice.

Resources