How do we solve the given scenario efficiently? - algorithm

We are given a maze in which we need to visit as many rooms as possible. The specialty of the maze is that once you enter any room it will only lead you to rooms with a higher tag in the direction you move . B and C decide to move in opposite directions trying their luck to maximize the number of rooms they search .(They can start with any room , need not be the same)
We need to find out the maximum number of rooms that can be searched.
1. Access to any room with a higher tag is allowed, not just adjacent rooms or the next room with a higher tag.
2. Tags are unique.
So given the input:
12 11 10 1 2 3 4 13 6 7 8 5 9
the answer is 12: (1,2,3,4,6,7,8,9) for B and (5,10,11,12) for C.
I thought of solving this using longest increasing sub sequence first from right and then from left.And the count of unique elements in above two sub sequence would be the answer.
But my logic seems to fail,how can this be done?

My program below computes the maximum number of rooms searched. This has time complexity of O(n^3). I modified the DP algorithm for computing the longest increasing sequence available online to solve OP's problem. This also addresses OP's concerns on arrays like {1,4,6,2,5}. I rightly get the max value as 5 for the previous example. So, I used the idea from #BeyelerStudios that we need to compute the longest increasing subsequence from both left to right and from right to left. But, there is a caveat. If we compute the Left to right max sequence, the sequence from right to left should be on the remaining elements. Example:
For the array {1, 4, 6, 2, 5}. If the forward rooms selected are {1, 4, 5 }, then the reverse longest increasing sequence should be computed on the left out elements {6, 2}.
Below is my program:
#include <iostream>
using namespace std;
// compute the max increasing sequence from right to left.
int r2lRooms (int arr[], int n)
{
int dp[n];
int i =0, j = 0;
int max = 0;
for ( i = 0; i < n; i++ ) {
dp[i] = 1;
}
for (i = n-2; i >= 0; i--) {
for ( j = n-1; j > i; j-- ) {
if ( arr[i] > arr[j] && dp[i] < dp[j] + 1) {
dp[i] = dp[j] + 1;
}
}
}
for ( i = 0; i < n; i++ ) {
if ( max < dp[i] ) {
max = dp[i];
}
}
return max;
}
// compute max rooms.
int maxRooms( int arr[], int n )
{
int dp[n], revArray[n];
int i =0, j = 0, k = 0;
int currentMax = 0;
int forwardMax = 0, reverseMax = 0;
for ( i = 0; i < n; i++ ) {
dp[i] = 1;
}
// First case is that except for first elem, all others are in revArray
for (i=1; i < n; i++, k++) {
revArray[k] = arr[i];
}
reverseMax = r2lRooms (revArray, k);
forwardMax = 1;
if (currentMax < (forwardMax + reverseMax)) {
currentMax = forwardMax + reverseMax;
}
cout << "forwardmax revmax and currentmax are: " << forwardMax << " " << reverseMax << " " << currentMax << endl;
cout << endl;
for ( i = 1; i < n; i++ ) {
k = 0;
forwardMax = 1;
reverseMax = 0;
cout << "Forward elems for arr[" << i << "]=" << arr[i] << endl;
for ( j = 0; j < i; j++ ) {
if ( arr[i] > arr[j] && dp[i] < dp[j] + 1) {
dp[i] = dp[j] + 1;
forwardMax = dp[i];
cout << arr[j] << " ";
}
else {
// element was not in DP calculation, so put in revArray.
revArray[k] = arr[j];
k++;
}
}
// copy the remaining elements in revArray.
for ( j = i+1; j < n; j++ ) {
revArray[k] = arr[j];
k++;
}
cout << endl;
reverseMax = r2lRooms (revArray, k);
if (currentMax < (forwardMax + reverseMax)) {
currentMax = forwardMax + reverseMax;
}
cout << "forwardmax revmax and currentmax are: " << forwardMax << " " << reverseMax << " " << currentMax << endl;
cout << endl;
}
cout << " Max rooms searched " << currentMax << endl;
return currentMax;
}
int main (void) {
int arr[] = {12, 11, 10, 1, 2, 3, 4, 13, 6, 7, 8, 5, 9 };
int size = sizeof(arr) / sizeof(int);
cout << maxRooms (arr, size);
}

I think the trick is at the intersection, where B and C might share a value or there's options to go around that (say the sequence is 12 11 10 1 2 3 4 <3 5> 13 6 7 8 9 The extra numbers here adds 1 to the solution, but doesn't change the result for either longest increasing sub-sequences.
So the only problem is the one room in the middle, since on both side the values chosen diverge.
What I would do is this: do the longest subsequence in one direction, figure out a solution (any solution), take out the numbers in the solution and do the longest subsequence in the other direction. This way if there's a way around the crossing room in the middle the second pass will prefer it, unless that's the chosen number is really needed. To check for that do the same thing, but build the first subsequence in the opposite direction and the second one (after removing the solution) in the direction chosen initially.
Complexity remains O(N) but with a slightly higher constant factor.

Related

find all common part between vector

I have n vectors with unique integers. I want to find all the common part between them. Is there any specific algorithm or data struct for this problem?
example:
std::vector<int> a = {0,1,2,3,4,5,6,7,8,9,10,11,12,13};
std::vector<int> b = {1,7,8,9,2,10,11,12};
std::vector<int> c = {4,9,8,7,0,1,2,3};
result:
ignore result with only one interge
7,8,9 between a and b
10,11,12 bewteen a and b
0,1,2,3 between a and c
if you want all common subarrays with a length greater than 1, then for each element from the first array iterate over all elements in the second array if you match two elements then go to the next element in the first and second array, and so on.
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (arr1[i] == arr2[j]) {
int ii = i, jj = j, cnt = 0;
std::vector<int> res;
res.push_back(arr1[ii]);
while (++ii < n and ++jj < m and arr1[ii] == arr2[jj])res.push_back(arr1[ii]);
if (res.size() > 1) {
for (auto x: res)std::cout << x << " ";
}
}
}
}
time complexity:O(n^3)
and this another way by LCS.
memset(dp, 0, sizeof dp);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
dp[i][j] = 0;
if (arr1[i] == arr2[j]) {
dp[i][j] = dp[i - 1][j - 1] + 1;
}
std::cout << dp[i][j] << " ";
}
std::cout << "\n";
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (dp[i][j] > 1) {
for (int ii = i, jj = j, k = dp[i][j]; k; ii--, jj--, k--) {
std::cout << arr1[ii] << " ";
}
std::cout << "\n";
}
}
}
O(n^3)
It seems to me that you are looking for Longest Common Subsequence
These images are calculated by a diff like program which compares lines (unordered), like shortest edit distance
Blue lines : Deleted lines to come from left to right
Red lines : Changed lines
Green lines: Inserted lines
Lines without color are unchanged = longest common subsequence. Diff result looks pretty much the same as the given results.
Reference:
A Fast Algorithm for computing longest common subsequences
by James W. Hunt and Thomas G. Szymanski
from Communications of the ACM May 1977 Volume 20 no. 5

Numbers of specified length that can be made using individual elements from an array

Let's say we have given an array of digits, A, and a positive number, B. The problem is to generate all the possible B-digit numbers combined of A's elements.
For example, if A = [0,1,2,3] and B = 2, then the output must be,
[10,11,12,13,20,21,22,23,30,31,32,33]
Generate all possible combinations​ of 2 digit numbers by multiplying and adding the elements of the array in nested for loops.
Check if the generated numbers are greater than 10 to be a valid two digit number.
`
#include<iostream>
#include<cmath>
int main () {
int A[4] = {0,1,2,3}; int B = 2; int k;
for(size_t i = 0; i < sizeof(A)/sizeof(A[0]); i++)
{
for(size_t j = 0; j < sizeof(A)/sizeof(A[0]); j++)
{
k = (A[i] * pow(10, B-1) + j);
if(k / 10 > 0)
std::cout << k << '\n';
}
}
}

C++ - Queue pop not working corrrectly using using for() loop

While writing a simple code using STL queue and for loop, I faced a problem. My procedure is simple: take a number as a string, convert them into queue elements and show them.
My code is below :
#include<iostream>
#include<queue>
#include<string>
//#include<cctype>
using namespace std;
//int to_words(int i);
//int to_words_one(queue<int> &q);
int main()
{
queue<int> q;
string s;
cout << "Enter a number not more than 12 digits : ";
getline(cin, s, '\n');
for (int i = 0; i < s.length(); i++)
{
if (!isdigit(s[i]))
{
cout << "Not a valid number." << endl;
s.clear();
break;
}
}
if(s.size() > 0)
for (int i = 0; i < s.length(); i++)
q.push(s[i] - '0');
while (!q.empty())
{
cout << q.front();
q.pop();
}
system("PAUSE");
}
It works fine. No problem. But instead of while(!q.empty()), if I use
for(int j=0;j < q.size(); j++)
{
cout << q.front();
q.pop();
}
It doesn't work properly! It just shows and pops some first elements , and NOT ALL elements of the queue and prompts for Press any key to continue. Please tell me why is this happening? Shouldn't while(!q.empty()) and and that for() loop work similar?
The problem is that q.size() decreases after each q.pop() and is evaluated in each iteration of the for loop. For instance, let's say you had 6 elements in your queue, the for loop state in subsequent iterations will be as below:
i = 0, q.size() = 6,
i = 1, q.size() = 5,
i = 2, q.size() = 4,
i = 3, q.size() = 3,
so only first 3 elements would be printed. If you want to use a for loop, save q.size() to a variable before the first iteration, like this:
int q_size = q.size();
for (int i = 0; i < q_size; i++) {
// do something
}
By calling queue::pop size of queue is decremented, so suppose you entered 8 digits, in first iteration of for loop q.size() returns 8, then you compare j < 8 it is true and j is incremented and size of queue is decremented. In the next iteration of loop for you compare j < 7, where j is 1. Do 2-th, 3-th iterations... After 4-th iterations j counter has value 4, and size of queue is 4 too, so condition j < 4 returns false, and only 4 digits were printed.

Dynamic Programming Coin Change Limited Coins

Dynamic Programming Change Problem (Limited Coins).
I'm trying to create a program that takes as INPUT:
int coinValues[]; //e.g [coin1,coin2,coin3]
int coinLimit[]; //e.g [2 coin1 available,1 coin2 available,...]
int amount; //the amount we want change for.
OUTPUT:
int DynProg[]; //of size amount+1.
And output should be an Array of size amount+1 of which each cell represents the optimal number of coins we need to give change for the amount of the cell's index.
EXAMPLE: Let's say that we have the cell of Array at index: 5 with a content of 2.
This means that in order to give change for the amount of 5(INDEX), you need 2(cell's content) coins (Optimal Solution).
Basically I need exactly the output of the first array of this video(C[p])
. It's exactly the same problem with the big DIFFERENCE of LIMITED COINS.
Link to Video.
Note: See the video to understand, ignore the 2nd array of the video, and have in mind that I don't need the combinations, but the DP array, so then I can find which coins to give as change.
Thank you.
Consider the next pseudocode:
for every coin nominal v = coinValues[i]:
loop coinLimit[i] times:
starting with k=0 entry, check for non-zero C[k]:
if C[k]+1 < C[k+v] then
replace C[k+v] with C[k]+1 and set S[k+v]=v
Is it clear?
O(nk) solution from an editorial I wrote a while ago:
We start with the basic DP solution that runs in O(k*sum(c)). We have our dp array, where dp[i][j] stores the least possible number of coins from the first i denominations that sum to j. We have the following transition: dp[i][j] = min(dp[i - 1][j - cnt * value[i]] + cnt) for cnt from 0 to j / value[i].
To optimize this to an O(nk) solution, we can use a deque to memorize the minimum values from the previous iteration and make the transitions O(1). The basic idea is that if we want to find the minimum of the last m values in some array, we can maintain an increasing deque that stores possible candidates for the minimum. At each step, we pop off values at the end of the deque greater than the current value before pushing the current value into the back deque. Since the current value is both further to the right and less than the values we popped off, we can be sure they will never be the minimum. Then, we pop off the first element in the deque if it is more than m elements away. The minimum value at each step is now simply the first element in the deque.
We can apply a similar optimization trick to this problem. For each coin type i, we compute the elements of the dp array in this order: For each possible value of j % value[i] in increasing order, we process the values of j which when divided by value[i] produces that remainder in increasing order. Now we can apply the deque optimization trick to find min(dp[i - 1][j - cnt * value[i]] + cnt) for cnt from 0 to j / value[i] in constant time.
Pseudocode:
let n = number of coin denominations
let k = amount of change needed
let v[i] = value of the ith denomination, 1 indexed
let c[i] = maximum number of coins of the ith denomination, 1 indexed
let dp[i][j] = the fewest number of coins needed to sum to j using the first i coin denominations
for i from 1 to k:
dp[0][i] = INF
for i from 1 to n:
for rem from 0 to v[i] - 1:
let d = empty double-ended-queue
for j from 0 to (k - rem) / v[i]:
let currval = rem + v[i] * j
if dp[i - 1][currval] is not INF:
while d is not empty and dp[i - 1][d.back() * v[i] + rem] + j - d.back() >= dp[i - 1][currval]:
d.pop_back()
d.push_back(j)
if d is not empty and j - d.front() > c[i]:
d.pop_front()
if d is empty:
dp[i][currval] = INF
else:
dp[i][currval] = dp[i - 1][d.front() * v[i] + rem] + j - d.front()
This is what you are looking for.
Assumptions made : Coin Values are in descending order
public class CoinChangeLimitedCoins {
public static void main(String[] args) {
int[] coins = { 5, 3, 2, 1 };
int[] counts = { 2, 1, 2, 1 };
int target = 9;
int[] nums = combine(coins, counts);
System.out.println(minCount(nums, target, 0, 0, 0));
}
private static int minCount(int[] nums, int target, int sum, int current, int count){
if(current > nums.length) return -1;
if(sum == target) return count;
if(sum + nums[current] <= target){
return minCount(nums, target, sum+nums[current], current+1, count+1);
} else {
return minCount(nums, target, sum, current+1, count);
}
}
private static int[] combine(int[] coins, int[] counts) {
int sum = 0;
for (int count : counts) {
sum += count;
}
int[] returnArray = new int[sum];
int returnArrayIndex = 0;
for (int i = 0; i < coins.length; i++) {
int count = counts[i];
while (count != 0) {
returnArray[returnArrayIndex] = coins[i];
returnArrayIndex++;
count--;
}
}
return returnArray;
}
}
You can check this question: Minimum coin change problem with limited amount of coins.
BTW, I created c++ program based above link's algorithm:
#include <iostream>
#include <map>
#include <vector>
#include <algorithm>
#include <limits>
using namespace std;
void copyVec(vector<int> from, vector<int> &to){
for(vector<int>::size_type i = 0; i < from.size(); i++)
to[i] = from[i];
}
vector<int> makeChangeWithLimited(int amount, vector<int> coins, vector<int> limits)
{
vector<int> change;
vector<vector<int>> coinsUsed( amount + 1 , vector<int>(coins.size()));
vector<int> minCoins(amount+1,numeric_limits<int>::max() - 1);
minCoins[0] = 0;
vector<int> limitsCopy(limits.size());
copy(limits.begin(), limits.end(), limitsCopy.begin());
for (vector<int>::size_type i = 0; i < coins.size(); ++i)
{
while (limitsCopy[i] > 0)
{
for (int j = amount; j >= 0; --j)
{
int currAmount = j + coins[i];
if (currAmount <= amount)
{
if (minCoins[currAmount] > minCoins[j] + 1)
{
minCoins[currAmount] = minCoins[j] + 1;
copyVec(coinsUsed[j], coinsUsed[currAmount]);
coinsUsed[currAmount][i] += 1;
}
}
}
limitsCopy[i] -= 1;
}
}
if (minCoins[amount] == numeric_limits<int>::max() - 1)
{
return change;
}
copy(coinsUsed[amount].begin(),coinsUsed[amount].end(), back_inserter(change) );
return change;
}
int main()
{
vector<int> coins;
coins.push_back(20);
coins.push_back(50);
coins.push_back(100);
coins.push_back(200);
vector<int> limits;
limits.push_back(100);
limits.push_back(100);
limits.push_back(50);
limits.push_back(20);
int amount = 0;
cin >> amount;
while(amount){
vector<int> change = makeChangeWithLimited(amount,coins,limits);
for(vector<int>::size_type i = 0; i < change.size(); i++){
cout << change[i] << "x" << coins[i] << endl;
}
if(change.empty()){
cout << "IMPOSSIBE\n";
}
cin >> amount;
}
system("pause");
return 0;
}
Code in c#
private static int MinCoinsChangeWithLimitedCoins(int[] coins, int[] counts, int sum)
{
var dp = new int[sum + 1];
Array.Fill(dp, int.MaxValue);
dp[0] = 0;
for (int i = 0; i < coins.Length; i++) // n
{
int coin = coins[i];
for (int j = 0; j < counts[i]; j++) //
{
for (int s = sum; s >= coin ; s--) // sum
{
int remainder = s - coin;
if (remainder >= 0 && dp[remainder] != int.MaxValue)
{
dp[s] = Math.Min(1 + dp[remainder], dp[s]);
}
}
}
}
return dp[sum] == int.MaxValue ? -1 : dp[sum];
}

Dividing an array into K subsets such that sum of all subsets is same using bitmasks+DP

So, this problem I dont have any clue how to solve it the problem statement is :
Given a set S of N integers the task is decide if it is possible to
divide them into K non-empty subsets such that the sum of elements in
every of the K subsets is equal.
N can be at max 20. K can be at max 8
The problem is to be solved specifically using DP+Bitmasks!
I cannot understand where to start ! As there are K sets to be maintained , I cannot take K states each representing some or the other!!
If I try taking the whole set as a state and K as the other, I have issues in creating a recurrent relation!
Can you help??
The link to original problem Problem
You can solve the problem in O(N * 2^N), so the K is meaningless for the complexity.
First let me warn you about the corner case N < K with all the numbers being zero, in which the answer is "no".
The idea of my algorithm is the following. Assume we have computed the sum of each of the masks (that can be done in O(2^N)). We know that for each of the groups, the sum should be the total sum divided by K.
We can do a DP with masks in which the state is just a binary mask telling which numbers have been used. The key idea in removing the K from the algorithm complexity is noticing that if we know which numbers have been used, we know the sum so far, so we also know which group we are filling now (current sum / group sum). Then just try to select the next number for the group: it will be valid if we do not exceed the group expected sum.
You can check my C++ code:
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
typedef long long ll;
ll v[21 + 5];
ll sum[(1 << 21) + 5];
ll group_sum;
int n, k;
void compute_sums(int position, ll current_sum, int mask)
{
if (position == -1)
{
sum[mask] = current_sum;
return;
}
compute_sums(position - 1, current_sum, mask << 1);
compute_sums(position - 1, current_sum + v[position], (mask << 1) + 1);
}
void solve_case()
{
cin >> n >> k;
for (int i = 0; i < n; ++i)
cin >> v[i];
memset(sum, 0, sizeof(sum));
compute_sums(n - 1, 0, 0);
group_sum = sum[(1 << n) - 1];
if (group_sum % k != 0)
{
cout << "no" << endl;
return;
}
if (group_sum == 0)
{
if (n >= k)
cout << "yes" << endl;
else
cout << "no" << endl;
return;
}
group_sum /= k;
vector<int> M(1 << n, 0);
M[0] = 1;
for (int mask = 0; mask < (1 << n); ++mask)
{
if (M[mask])
{
int current_group = sum[mask] / group_sum;
for (int i = 0; i < n; ++i)
{
if ((mask >> i) & 1)
continue;
if (sum[mask | (1 << i)] <= group_sum * (current_group + 1))
M[mask | (1 << i)] = 1;
}
}
}
if (M[(1 << n) - 1])
cout << "yes" << endl;
else
cout << "no" << endl;
}
int main()
{
int cases;
cin >> cases;
for (int z = 1; z <= cases; ++z)
solve_case();
}
Here's the working O(K*2^N*N) implementation in JavaScript. From the pseudo code https://discuss.codechef.com/questions/58420/sanskar-editorial
http://jsfiddle.net/d7q4o0nj/
function equality(set, size, count) {
if(size < count) { return false; }
var total = set.reduce(function(p, c) { return p + c; }, 0);
if((total % count) !== 0) { return false }
var subsetTotal = total / count;
var search = {0: true};
var nextSearch = {};
for(var i=0; i<count; i++) {
for(var bits=0; bits < (1 << size); bits++){
if(search[bits] !== true) { continue; }
var sum = 0;
for(var j=0; j < size; j++) {
if((bits & (1 << j)) !== 0) { sum += set[j]; }
}
sum -= i * subsetTotal;
for(var j=0; j < size; j++) {
if((bits & (1 << j)) !== 0) { continue; }
var testBits = bits | (1 << j);
var tmpTotal = sum + set[j];
if(tmpTotal == subsetTotal) { nextSearch[testBits] = true; }
else if(tmpTotal < subsetTotal) { search[testBits] = true; }
}
}
search = nextSearch;
nextSearch = {};
}
if(search[(1 << size) - 1] === true) {
return true;
}
return false;
}
console.log(true, equality([1,2,3,1,2,3], 6, 2));
console.log(true, equality([1, 2, 4, 5, 6], 5, 3));
console.log(true, equality([10,20,10,20,10,20,10,20,10,20], 10, 5));
console.log(false, equality([1,2,4,5,7], 5, 3));
EDIT The algorithm finds all of the bitmasks (which represent subsets bits) that meet the criteria (having a sum tmpTotal less than or equal to the ideal subset sum subsetTotal). Repeating this process by the amount of subsets required count, you either have a bitmask where all size bits are set which means success or the test fails.
EXAMPLE
set = [1, 2, 1, 2]
size = 4
count = 2, we want to try to partition the set into 2 subsets
subsetTotal = (1+2+1+2) / 2 = 3
Iteration 1:
search = {0b: true, 1b: true, 10b: true, 100b: true, 1000b: true, 101b: true}
nextSearch = {11b: true, 1100b: true, 110b: true, 1001b: true }
Iteration 2:
search = {11b: true, 1100b: true, 110b: true, 1001b: true, 111b: true, 1101b: true }
nextSearch = {1111b: true}
Final Check
(1 << size) == 10000b, (1 << size) - 1 == 1111b
Since nextSearch[ 1111b ] exists we return success.
UPD: I confused N and K with each other and my idea is true but not efficient.Efficient idea added at the end
Assume that so far you've created k-1 subsets, and now you want to create the k-th subset. For creating the k-th subset, you need to be able to answer these two questions:
1- What should be the sum of elements of k-th subset?
2- Which elements have been used so far ?
Answering the first question is easy, the sum should be equal to sum of all elements divided by K, let's name it subSum.
For second question, we need to have the state of each element, used or not. Here we need to use bitmask idea.
Here's the dp recurrence:
dp[i][mask] = means is it possible to create i subsets with sum of each equals to subSum, using the elements which are 1(not used) in mask (in its bit representation), So dp[i][mask] is a boolean type.
dp[i][mask] = OR(dp[i-1][mask2]) for all possible mask2 states. mask2 will be produced by converting some 1's of mask to 0's, i.e. those 1's that we want to be the elements of i-th subset.
For checking all possible mask2, you need to check all 2^n possible subsets of available 1's bits.Therefore, totaly, the time complexity will be O(N*(2^n)*(2^n)). In your problem is 20*2^8*2^8= 10*2^17 < 10^7 which can pass the time limit.
Obviously, for base case you have to handle dp[0][mask] on your own, without using the recurrence.Final answer is whether dp[K][2^N-1] is true or not.
__UPD__: For getting a better performance,before get into DP, you could preprocess all subsets with sum of subSum. Then, for calculating mask2, you just need to iterate over the preprocessed list, and see whether the AND operation of them with mask would result in the subset in the list or not.
UPD2:
For having an efficient solution, instead of finding proper mask2, we could use the fact that at each step, we know the sum of elements till that point. So we could add elements one by one into the mask, and whenever we had a sum which is divisible by K we could go to the next step for creating next subset.
if (sum of used elements of mask is divisible by K)
dp[i][mask]= dp[i+1][mask];
else
dp[i][mask]|=dp[i][mask ^(1<<i)] provided that i-th item is not used and can not exceed the current sum more than i*subSum.

Resources