Related
I have to find the best algorithm to define pairing between the items from two lists as in the figure. The pair is valid only if the number of node in list A is lower than number of node in list B and there are no crosses between links. The quality of the matching algorithm is determined by the total number of links.
I firstly tried to use a very simple algorithm: take a node in the list A and then look for the first node in list B that is higher than the former. The second figure shows a test case where this algorithm is not the best one.
Simple back-tracking can work (it may not be optimal, but it will certainly work).
For each legal pairing A[i], B[j], there are two choices:
take it, and make it illegal to try to pair any A[x], B[y] with x>i and y<j
not take it, and look at other possible pairs
By incrementally adding legal pairs to a bunch of pairs, you will eventually exhaust all legal pairings down a path. The number of valid pairings in a path is what you seek to maximize, and this algorithm will look at all possible answers and is guaranteed to work.
Pseudocode:
function search(currentPairs):
bestPairing = currentPairs
for each currently legal pair:
nextPairing = search(copyOf(currentPairs) + this pair)
if length of nextPairing > length of bestPairing:
bestPairing = nextPairing
return bestPairing
Initially, you will pass an empty currentPairs. Searching for legal pairs is the tricky part. You can use 3 nested loops that look at all A[x], B[y], and finally, if A[x] < B[y], look against all currentPairs to see if the there is a crossing line (the cost of this is roughly O(n^3)); or you can use a boolean matrix of valid pairings, which you update at each level (less computation time, down to O(n^2) - but more expensive in terms of memory)
Here a Java implementation.
For convinience I first build a map with the valid choices for each entry of list(array) a to b.
Then I loop throuough the list, making no choice and the valid choices for a connection to b.
Since you cant go back without crossing the existing connections I keep track of the maximum assigned in b.
Works at least for the two examples...
public class ListMatcher {
private int[] a ;
private int[] b ;
private Map<Integer,List<Integer>> choicesMap;
public ListMatcher(int[] a, int[] b) {
this.a = a;
this.b = b;
choicesMap = makeMap(a,b);
}
public Map<Integer,Integer> solve() {
Map<Integer,Integer> solution = new HashMap<>();
return solve(solution, 0, -1);
}
private Map<Integer,Integer> solve(Map<Integer,Integer> soFar, int current, int max) {
// done
if (current >= a.length) {
return soFar;
}
// make no choice from this entry
Map<Integer, Integer> solution = solve(new HashMap<>(soFar),current+1, max);
for (Integer choice : choicesMap.get(current)) {
if (choice > max) // can't go back
{
Map<Integer,Integer> next = new HashMap<>(soFar);
next.put(current, choice);
next = solve(next, current+1, choice);
if (next.size() > solution.size()) {
solution = next;
}
}
}
return solution;
}
// init possible choices
private Map<Integer, List<Integer>> makeMap(int[] a, int[] b) {
Map<Integer,List<Integer>> possibleMap = new HashMap<>();
for(int i = 0; i < a.length; i++) {
List<Integer> possible = new ArrayList<>();
for(int j = 0; j < b.length; j++) {
if (a[i] < b[j]) {
possible.add(j);
}
}
possibleMap.put(i, possible);
}
return possibleMap;
}
public static void main(String[] args) {
ListMatcher matcher = new ListMatcher(new int[]{3,7,2,1,5,9,2,2},new int[]{4,5,10,1,12,3,6,7});
System.out.println(matcher.solve());
matcher = new ListMatcher(new int[]{10,1,1,1,1,1,1,1},new int[]{2,2,2,2,2,2,2,101});
System.out.println(matcher.solve());
}
}
Output
(format: zero-based index_in_a=index_in_b)
{2=0, 3=1, 4=2, 5=4, 6=5, 7=6}
{1=0, 2=1, 3=2, 4=3, 5=4, 6=5, 7=6}
Your solution isn't picked because the solutions making no choice are picked first.
You can change this by processing the loop first...
Thanks to David's suggestion, I finally found the algorithm. It is an LCS approach, replacing the '=' with an '>'.
Recursive approach
The recursive approach is very straightforward. G and V are the two vectors with size n and m (adding a 0 at the beginning of both). Starting from the end, if last from G is larger than last from V, then return 1 + the function evaluated without the last item, otherwise return max of the function removing last from G or last from V.
int evaluateMaxRecursive(vector<int> V, vector<int> G, int n, int m) {
if ((n == 0) || (m == 0)) {
return 0;
}
else {
if (V[n] < G[m]) {
return 1 + evaluateMaxRecursive(V, G, n - 1, m - 1);
} else {
return max(evaluateMaxRecursive(V, G, n - 1, m), evaluateMaxRecursive(V, G, n, m - 1));
}
}
};
The recursive approach is valid with small number of items, due to the re-evaluation of same lists that occur during the loop.
Non recursive approach
The non recursive approach goes in the opposite direction and works with a table that is filled in after having clared to 0 first row and first column. The max value is the value in the bottom left corner of the table
int evaluateMax(vector<int> V, vector<int> G, int n, int m) {
int** table = new int* [n + 1];
for (int i = 0; i < n + 1; ++i)
table[i] = new int[m + 1];
for (int i = 0; i < n + 1; i++)
for (int t = 0; t < m + 1; t++)
table[i][t] = 0;
for (int i = 1; i < m + 1; i++)
for (int t = 1; t < n + 1; t++) {
if (G[i - 1] > V[t - 1]) {
table[t] [i] = 1 + table[t - 1][i - 1];
}
else {
table[t][i] = max(table[t][i - 1], table[t - 1][i]);
}
}
return table[n][m];
}
You can find more details here LCS - Wikipedia
Question link: http://codeforces.com/contest/2/problem/B
There is a square matrix n × n, consisting of non-negative integer numbers. You should find such a way on it that
starts in the upper left cell of the matrix;
each following cell is to the right or down from the current cell;
the way ends in the bottom right cell.
Moreover, if we multiply together all the numbers along the way, the result should be the least "round". In other words, it should end in the least possible number of zeros.
Input
The first line contains an integer number n (2 ≤ n ≤ 1000), n is the size of the matrix. Then follow n lines containing the matrix elements (non-negative integer numbers not exceeding 10^9).
Output
In the first line print the least number of trailing zeros. In the second line print the correspondent way itself.
I thought of the following: In the end, whatever the answer will be, it should contain minimum powers of 2's and 5's. Therefore, what I did was, for each entry in the input matrix, I calculated the powers of 2's and 5's and stored them in separate matrices.
for (i = 0; i < n; i++)
{
for ( j = 0; j < n; j++)
{
cin>>foo;
matrix[i][j] = foo;
int n1 = calctwo(foo); // calculates the number of 2's in factorisation of that number
int n2 = calcfive(foo); // calculates number of 5's
two[i][j] = n1;
five[i][j] = n2;
}
}
After that, I did this:
for (i = 0; i < n; i++)
{
for ( j = 0; j < n; j++ )
{
dp[i][j] = min(two[i][j],five[i][j]); // Here, dp[i][j] will store minimum number of 2's and 5's.
}
}
But the above doesn't really a valid answer, I don't know why? Have I implemented the correct approach? Or, is this the correct way of solving this question?
Edit: Here are my functions of calculating the number of two's and number of five's in a number.
int calctwo (int foo)
{
int counter = 0;
while (foo%2 == 0)
{
if (foo%2 == 0)
{
counter++;
foo = foo/2;
}
else
break;
}
return counter;
}
int calcfive (int foo)
{
int counter = 0;
while (foo%5 == 0)
{
if (foo%5 == 0)
{
counter++;
foo = foo/5;
}
else
break;
}
return counter;
}
Edit2: I/O Example as given in the link:
Input:
3
1 2 3
4 5 6
7 8 9
Output:
0
DDRR
Since you are interested only in the number of trailing zeroes you need only to consider the powers of 2, 5 which you could keep in two separate nxn arrays. So for the array
1 2 3
4 5 6
7 8 9
you just keep the arrays
the powers of 2 the powers of 5
0 1 0 0 0 0
2 0 1 0 1 0
0 3 0 0 0 0
The insight for the problem is the following. Notice that if you find a path which minimizes the sum of the powers of 2 and a path which minimizes the number sum of the powers of 5 then the answer is the one with lower value of those two paths. So you reduce your problem to the two times application of the following classical dp problem: find a path, starting from the top-left corner and ending at the bottom-right, such that the sum of its elements is minimum. Again, following the example, we have:
minimal path for the
powers of 2 value
* * - 2
- * *
- - *
minimal path for the
powers of 5 value
* - - 0
* - -
* * *
so your answer is
* - -
* - -
* * *
with value 0
Note 1
It might seem that taking the minimum of the both optimal paths gives only an upper bound so a question that may rise is: is this bound actually achieved? The answer is yes. For convenience, let the number of 2's along the 2's optimal path is a and the number of 5's along the 5's optimal path is b. Without loss of generality assume that the minimum of the both optimal paths is the one for the power of 2's (that is a < b). Let the number of 5's along the minimal path is c. Now the question is: are there as much as 5's as there are 2's along this path (i.e. is c >= a?). Assume that the answer is no. That means that there are less 5's than 2's along the minimal path (that is c < a). Since the optimal value of 5's paths is b we have that every 5's path has at least b 5's in it. This should also be true for the minimal path. That means that c > b. We have that c < a so a > b but the initial assumption was that a < b. Contradiction.
Note 2
You might also want consider the case in which there is an element 0 in your matrix. I'd assume that number of trailing zeroes when the product is 1. In this case, if the algorithm has produced a result with a value more than 1 you should output 1 and print a path that goes through the element 0.
Here is the code. I've used pair<int,int> to store factor of 2 and 5 in the matrix.
#include<vector>
#include<iostream>
using namespace std;
#define pii pair<int,int>
#define F first
#define S second
#define MP make_pair
int calc2(int a){
int c=0;
while(a%2==0){
c++;
a/=2;
}
return c;
}
int calc5(int a){
int c=0;
while(a%5==0){
c++;
a/=5;
}
return c;
}
int mini(int a,int b){
return a<b?a:b;
}
pii min(pii a, pii b){
if(mini(a.F,a.S) < mini(b.F,b.S))
return a;
return b;
}
int main(){
int n;
cin>>n;
vector<vector<pii > > v;
vector<vector<int> > path;
int i,j;
for(i=0;i<n;i++){
vector<pii > x;
vector<int> q(n,0);
for(j=0;j<n;j++){
int y;cin>>y;
x.push_back(MP(calc2(y),calc5(y))); //I store factors of 2,5 in the vector to calculate
}
x.push_back(MP(100000,100000)); //padding each row to n+1 elements (to handle overflow in code)
v.push_back(x);
path.push_back(q); //initialize path matrix to 0
}
vector<pii > x(n+1,MP(100000,100000));
v.push_back(x); //pad 1 more row to handle index overflow
for(i=n-1;i>=0;i--){
for(j=n-1;j>=0;j--){ //move from destination to source grid
if(i==n-1 && j==n-1)
continue;
//here, the LHS of condition in if block is the condition which determines minimum number of trailing 0's. This is the same condition that is used to manipulate "v" for getting the same result.
if(min(MP(v[i][j].F+v[i+1][j].F,v[i][j].S+v[i+1][j].S), MP(v[i][j].F+v[i][j+1].F,v[i][j].S+v[i][j+1].S)) == MP(v[i][j].F+v[i+1][j].F,v[i][j].S+v[i+1][j].S))
path[i][j] = 1; //go down
else
path[i][j] = 2; //go right
v[i][j] = min(MP(v[i][j].F+v[i+1][j].F,v[i][j].S+v[i+1][j].S), MP(v[i][j].F+v[i][j+1].F,v[i][j].S+v[i][j+1].S));
}
}
cout<<mini(v[0][0].F, v[0][0].S)<<endl; //print result
for(i=0,j=0;i<=n-1 && j<=n-1;){ //print path (I don't know o/p format)
cout<<"("<<i<<","<<j<<") -> ";
if(path[i][j]==1)
i++;
else
j++;
}
return 0;
}
This code gives fine results as far as the test cases I checked. If you have any doubts regarding this code, ask in comments.
EDIT:
The basic thought process.
To reach the destination, there are only 2 options. I started with destination to avoid the problem of path ahead calculation, because if 2 have same minimum values, then we chose any one of them. If the path to destination is already calculated, it does not matter which we take.
And minimum is to check which pair is more suitable. If a pair has minimum 2's or 5's than other, it will produce less 0's.
Here is a solution proposal using Javascript and functional programming.
It relies on several functions:
the core function is smallest_trailer that recursively goes through the grid. I have chosen to go in 4 possible direction, left "L", right "R", down "D" and "U". It is not possible to pass twice on the same cell. The direction that is chosen is the one with the smallest number of trailing zeros. The counting of trailing zeros is devoted to another function.
the function zero_trailer(p,n,nbz) assumes that you arrive on a cell with a value p while you already have an accumulator n and met nbz zeros on your way. The function returns an array with two elements, the new number of zeros and the new accumulator. The accumulator will be a power of 2 or 5. The function uses the auxiliary function pow_2_5(n) that returns the powers of 2 and 5 inside n.
Other functions are more anecdotical: deepCopy(arr) makes a standard deep copy of the array arr, out_bound(i,j,n) returns true if the cell (i,j) is out of bound of the grid of size n, myMinIndex(arr) returns the min index of an array of 2 dimensional arrays (each subarray contains the nb of trailing zeros and the path as a string). The min is only taken on the first element of subarrays.
MAX_SAFE_INTEGER is a (large) constant for the maximal number of trailing zeros when the path is wrong (goes out of bound for example).
Here is the code, which works on the example given in the comments above and in the orginal link.
var MAX_SAFE_INTEGER = 9007199254740991;
function pow_2_5(n) {
// returns the power of 2 and 5 inside n
function pow_not_2_5(k) {
if (k%2===0) {
return pow_not_2_5(k/2);
}
else if (k%5===0) {
return pow_not_2_5(k/5);
}
else {
return k;
}
}
return n/pow_not_2_5(n);
}
function zero_trailer(p,n,nbz) {
// takes an input two numbers p and n that should be multiplied and a given initial number of zeros (nbz = nb of zeros)
// n is the accumulator of previous multiplications (a power of 5 or 2)
// returns an array [kbz, k] where kbz is the total new number of zeros (nbz + the trailing zeros from the multiplication of p and n)
// and k is the new accumulator (typically a power of 5 or 2)
function zero_aux(k,kbz) {
if (k===0) {
return [1,0];
}
else if (k%10===0) {
return zero_aux(k/10,kbz+1);
}
else {
return [kbz,k];
}
}
return zero_aux(pow_2_5(p)*n,nbz);
}
function out_bound(i,j,n) {
return !((i>=0)&&(i<n)&&(j>=0)&&(j<n));
}
function deepCopy(arr){
var toR = new Array(arr.length);
for(var i=0;i<arr.length;i++){
var toRi = new Array(arr[i].length);
for(var j=0;j<arr[i].length;j++){
toRi[j] = arr[i][j];
}
toR[i] = toRi;
}
return toR;
}
function myMinIndex(arr) {
var min = arr[0][0];
var minIndex = 0;
for (var i = 1; i < arr.length; i++) {
if (arr[i][0] < min) {
minIndex = i;
min = arr[i][0];
}
}
return minIndex;
}
function smallest_trailer(grid) {
var n = grid.length;
function st_aux(i,j,grid_aux, acc_mult, nb_z, path) {
if ((i===n-1)&&(j===n-1)) {
var tmp_acc_nbz_f = zero_trailer(grid_aux[i][j],acc_mult,nb_z);
return [tmp_acc_nbz_f[0], path];
}
else if (out_bound(i,j,n)) {
return [MAX_SAFE_INTEGER,[]];
}
else if (grid_aux[i][j]<0) {
return [MAX_SAFE_INTEGER,[]];
}
else {
var tmp_acc_nbz = zero_trailer(grid_aux[i][j],acc_mult,nb_z) ;
grid_aux[i][j]=-1;
var res = [st_aux(i+1,j,deepCopy(grid_aux), tmp_acc_nbz[1], tmp_acc_nbz[0], path+"D"),
st_aux(i-1,j,deepCopy(grid_aux), tmp_acc_nbz[1], tmp_acc_nbz[0], path+"U"),
st_aux(i,j+1,deepCopy(grid_aux), tmp_acc_nbz[1], tmp_acc_nbz[0], path+"R"),
st_aux(i,j-1,deepCopy(grid_aux), tmp_acc_nbz[1], tmp_acc_nbz[0], path+"L")];
return res[myMinIndex(res)];
}
}
return st_aux(0,0,grid, 1, 0, "");
}
myGrid = [[1, 25, 100],[2, 1, 25],[100, 5, 1]];
console.log(smallest_trailer(myGrid)); //[0,"RDDR"]
myGrid = [[1, 2, 100],[25, 1, 5],[100, 25, 1]];
console.log(smallest_trailer(myGrid)); //[0,"DRDR"]
myGrid = [[1, 10, 1, 1, 1],[1, 1, 1, 10, 1],[10, 10, 10, 10, 1],[10, 10, 10, 10, 1],[10, 10, 10, 10, 1]];
console.log(smallest_trailer(myGrid)); //[0,"DRRURRDDDD"]
This is my Dynamic Programming solution.
https://app.codility.com/demo/results/trainingAXFQ5B-SZQ/
For better understanding we can simplify the task and assume that there are no zeros in the matrix (i.e. matrix contains only positive integers), then the Java solution will be the following:
class Solution {
public int solution(int[][] a) {
int minPws[][] = new int[a.length][a[0].length];
int minPws2 = getMinPws(a, minPws, 2);
int minPws5 = getMinPws(a, minPws, 5);
return min(minPws2, minPws5);
}
private int getMinPws(int[][] a, int[][] minPws, int p) {
minPws[0][0] = pws(a[0][0], p);
//Fullfill the first row
for (int j = 1; j < a[0].length; j++) {
minPws[0][j] = minPws[0][j-1] + pws(a[0][j], p);
}
//Fullfill the first column
for (int i = 1; i < a.length; i++) {
minPws[i][0] = minPws[i-1][0] + pws(a[i][0], p);
}
//Fullfill the rest of matrix
for (int i = 1; i < a.length; i++) {
for (int j = 1; j < a[0].length; j++) {
minPws[i][j] = min(minPws[i-1][j], minPws[i][j-1]) + pws(a[i][j], p);
}
}
return minPws[a.length-1][a[0].length-1];
}
private int pws(int n, int p) {
//Only when n > 0
int pws = 0;
while (n % p == 0) {
pws++;
n /= p;
}
return pws;
}
private int min(int a, int b) {
return (a < b) ? a : b;
}
}
I recently went through an interview and was asked this question. Let me explain the question properly:
Given a number M (N-digit integer) and K number of swap operations(a swap
operation can swap 2 digits), devise an algorithm to get the maximum
possible integer?
Examples:
M = 132 K = 1 output = 312
M = 132 K = 2 output = 321
M = 7899 k = 2 output = 9987
My solution ( algorithm in pseudo-code). I used a max-heap to get the maximum digit out of N-digits in each of the K-operations and then suitably swapping it.
for(int i = 0; i<K; i++)
{
int max_digit_currently = GetMaxFromHeap();
// The above function GetMaxFromHeap() pops out the maximum currently and deletes it from heap
int index_to_swap_with = GetRightMostOccurenceOfTheDigitObtainedAbove();
// This returns me the index of the digit obtained in the previous function
// .e.g If I have 436659 and K=2 given,
// then after K=1 I'll have 936654 and after K=2, I should have 966354 and not 963654.
// Now, the swap part comes. Here the gotcha is, say with the same above example, I have K=3.
// If I do GetMaxFromHeap() I'll get 6 when K=3, but I should not swap it,
// rather I should continue for next iteration and
// get GetMaxFromHeap() to give me 5 and then get 966534 from 966354.
if (Value_at_index_to_swap == max_digit_currently)
continue;
else
DoSwap();
}
Time complexity: O(K*( N + log_2(N) ))
// K-times [log_2(N) for popping out number from heap & N to get the rightmost index to swap with]
The above strategy fails in this example:
M = 8799 and K = 2
Following my strategy, I'll get M = 9798 after K=1 and M = 9978 after K=2. However, the maximum I can get is M = 9987 after K=2.
What did I miss?
Also suggest other ways to solve the problem & ways to optimize my solution.
I think the missing part is that, after you've performed the K swaps as in the algorithm described by the OP, you're left with some numbers that you can swap between themselves. For example, for the number 87949, after the initial algorithm we would get 99748. However, after that we can swap 7 and 8 "for free", i.e. not consuming any of the K swaps. This would mean "I'd rather not swap the 7 with the second 9 but with the first".
So, to get the max number, one would perform the algorithm described by the OP and remember the numbers which were moved to the right, and the positions to which they were moved. Then, sort these numbers in decreasing order and put them in the positions from left to right.
This is something like a separation of the algorithm in two phases - in the first one, you choose which numbers should go in the front to maximize the first K positions. Then you determine the order in which you would have swapped them with the numbers whose positions they took, so that the rest of the number is maximized as well.
Not all the details are clear, and I'm not 100% sure it handles all cases correctly, so if anyone can break it - go ahead.
This is a recursive function, which sorts the possible swap values for each (current-max) digit:
function swap2max(string, K) {
// the recursion end:
if (string.length==0 || K==0)
return string
m = getMaxDigit(string)
// an array of indices of the maxdigits to swap in the string
indices = []
// a counter for the length of that array, to determine how many chars
// from the front will be swapped
len = 0
// an array of digits to be swapped
front = []
// and the index of the last of those:
right = 0
// get those indices, in a loop with 2 conditions:
// * just run backwards through the string, until we meet the swapped range
// * no more swaps than left (K)
for (i=string.length; i-->right && len<K;)
if (m == string[i])
// omit digits that are already in the right place
while (right<=i && string[right] == m)
right++
// and when they need to be swapped
if (i>=right)
front.push(string[right++])
indices.push(i)
len++
// sort the digits to swap with
front.sort()
// and swap them
for (i=0; i<len; i++)
string.setCharAt(indices[i], front[i])
// the first len digits are the max ones
// the rest the result of calling the function on the rest of the string
return m.repeat(right) + swap2max(string.substr(right), K-len)
}
This is all pseudocode, but converts fairly easy to other languages. This solution is nonrecursive and operates in linear worst case and average case time.
You are provided with the following functions:
function k_swap(n, k1, k2):
temp = n[k1]
n[k1] = n[k2]
n[k2] = temp
int : operator[k]
// gets or sets the kth digit of an integer
property int : magnitude
// the number of digits in an integer
You could do something like the following:
int input = [some integer] // input value
int digitcounts[10] = {0, ...} // all zeroes
int digitpositions[10] = {0, ...) // all zeroes
bool filled[input.magnitude] = {false, ...) // all falses
for d = input[i = 0 => input.magnitude]:
digitcounts[d]++ // count number of occurrences of each digit
digitpositions[0] = 0;
for i = 1 => input.magnitude:
digitpositions[i] = digitpositions[i - 1] + digitcounts[i - 1] // output positions
for i = 0 => input.magnitude:
digit = input[i]
if filled[i] == true:
continue
k_swap(input, i, digitpositions[digit])
filled[digitpositions[digit]] = true
digitpositions[digit]++
I'll walk through it with the number input = 724886771
computed digitcounts:
{0, 1, 1, 0, 1, 0, 1, 3, 2, 0}
computed digitpositions:
{0, 0, 1, 2, 2, 3, 3, 4, 7, 9}
swap steps:
swap 0 with 0: 724886771, mark 0 visited
swap 1 with 4: 724876781, mark 4 visited
swap 2 with 5: 724778881, mark 5 visited
swap 3 with 3: 724778881, mark 3 visited
skip 4 (already visited)
skip 5 (already visited)
swap 6 with 2: 728776481, mark 2 visited
swap 7 with 1: 788776421, mark 1 visited
swap 8 with 6: 887776421, mark 6 visited
output number: 887776421
Edit:
This doesn't address the question correctly. If I have time later, I'll fix it but I don't right now.
How I would do it (in pseudo-c -- nothing fancy), assuming a fantasy integer array is passed where each element represents one decimal digit:
int[] sortToMaxInt(int[] M, int K) {
for (int i = 0; K > 0 && i < M.size() - 1; i++) {
if (swapDec(M, i)) K--;
}
return M;
}
bool swapDec(int[]& M, int i) {
/* no need to try and swap the value 9 as it is the
* highest possible value anyway. */
if (M[i] == 9) return false;
int max_dec = 0;
int max_idx = 0;
for (int j = i+1; j < M.size(); j++) {
if (M[j] >= max_dec) {
max_idx = j;
max_dec = M[j];
}
}
if (max_dec > M[i]) {
M.swapElements(i, max_idx);
return true;
}
return false;
}
From the top of my head so if anyone spots some fatal flaw please let me know.
Edit: based on the other answers posted here, I probably grossly misunderstood the problem. Anyone care to elaborate?
You start with max-number(M, N, 1, K).
max-number(M, N, pos, k)
{
if k == 0
return M
max-digit = 0
for i = pos to N
if M[i] > max-digit
max-digit = M[i]
if M[pos] == max-digit
return max-number(M, N, pos + 1, k)
for i = (pos + 1) to N
maxs.add(M)
if M[i] == max-digit
M2 = new M
swap(M2, i, pos)
maxs.add(max-number(M2, N, pos + 1, k - 1))
return maxs.max()
}
Here's my approach (It's not fool-proof, but covers the basic cases). First we'll need a function that extracts each DIGIT of an INT into a container:
std::shared_ptr<std::deque<int>> getDigitsOfInt(const int N)
{
int number(N);
std::shared_ptr<std::deque<int>> digitsQueue(new std::deque<int>());
while (number != 0)
{
digitsQueue->push_front(number % 10);
number /= 10;
}
return digitsQueue;
}
You obviously want to create the inverse of this, so convert such a container back to an INT:
const int getIntOfDigits(const std::shared_ptr<std::deque<int>>& digitsQueue)
{
int number(0);
for (std::deque<int>::size_type i = 0, iMAX = digitsQueue->size(); i < iMAX; ++i)
{
number = number * 10 + digitsQueue->at(i);
}
return number;
}
You also will need to find the MAX_DIGIT. It would be great to use std::max_element as it returns an iterator to the maximum element of a container, but if there are more you want the last of them. So let's implement our own max algorithm:
int getLastMaxDigitOfN(const std::shared_ptr<std::deque<int>>& digitsQueue, int startPosition)
{
assert(!digitsQueue->empty() && digitsQueue->size() > startPosition);
int maxDigitPosition(0);
int maxDigit(digitsQueue->at(startPosition));
for (std::deque<int>::size_type i = startPosition, iMAX = digitsQueue->size(); i < iMAX; ++i)
{
const int currentDigit(digitsQueue->at(i));
if (maxDigit <= currentDigit)
{
maxDigit = currentDigit;
maxDigitPosition = i;
}
}
return maxDigitPosition;
}
From here on its pretty straight what you have to do, put the right-most (last) MAX DIGITS to their places until you can swap:
const int solution(const int N, const int K)
{
std::shared_ptr<std::deque<int>> digitsOfN = getDigitsOfInt(N);
int pos(0);
int RemainingSwaps(K);
while (RemainingSwaps)
{
int lastHDPosition = getLastMaxDigitOfN(digitsOfN, pos);
if (lastHDPosition != pos)
{
std::swap<int>(digitsOfN->at(lastHDPosition), digitsOfN->at(pos));
++pos;
--RemainingSwaps;
}
}
return getIntOfDigits(digitsOfN);
}
There are unhandled corner-cases but I'll leave that up to you.
I assumed K = 2, but you can change the value!
Java code
public class Solution {
public static void main (String args[]) {
Solution d = new Solution();
System.out.println(d.solve(1234));
System.out.println(d.solve(9812));
System.out.println(d.solve(9876));
}
public int solve(int number) {
int[] array = intToArray(number);
int[] result = solve(array, array.length-1, 2);
return arrayToInt(result);
}
private int arrayToInt(int[] array) {
String s = "";
for (int i = array.length-1 ;i >= 0; i--) {
s = s + array[i]+"";
}
return Integer.parseInt(s);
}
private int[] intToArray(int number){
String s = number+"";
int[] result = new int[s.length()];
for(int i = 0 ;i < s.length() ;i++) {
result[s.length()-1-i] = Integer.parseInt(s.charAt(i)+"");
}
return result;
}
private int[] solve(int[] array, int endIndex, int num) {
if (endIndex == 0)
return array;
int size = num ;
int firstIndex = endIndex - size;
if (firstIndex < 0)
firstIndex = 0;
int biggest = findBiggestIndex(array, endIndex, firstIndex);
if (biggest!= endIndex) {
if (endIndex-biggest==num) {
while(num!=0) {
int temp = array[biggest];
array[biggest] = array[biggest+1];
array[biggest+1] = temp;
biggest++;
num--;
}
return array;
}else{
int n = endIndex-biggest;
for (int i = 0 ;i < n;i++) {
int temp = array[biggest];
array[biggest] = array[biggest+1];
array[biggest+1] = temp;
biggest++;
}
return solve(array, --biggest, firstIndex);
}
}else{
return solve(array, --endIndex, num);
}
}
private int findBiggestIndex(int[] array, int endIndex, int firstIndex) {
int result = firstIndex;
int max = array[firstIndex];
for (int i = firstIndex; i <= endIndex; i++){
if (array[i] > max){
max = array[i];
result = i;
}
}
return result;
}
}
I read through all subset sum topics and still have issues with implementing the algorithm for the following problem.
Given the array A of N integers (N<=20) where
a[i]<=20
values do not have to be unique
and an integer K (K<=20).
Rules:
Array items equal to K are "covered" with K.
If sum of two or more array numbers is equal to K, these numbers are also covered.
Each number in the array can be covered only once.
Example:
N=6, integers: 1, 1, 2, 3, 4, 5
K=4
Possible coverages:
coverage
4 is covered.
1, 1, 2 are covered as 1+1+2=4.
coverage
4 is covered.
1, 3 are covered as 1+3=4.
K=5
Possible coverages:
coverage
5 is covered.
1,1,3 are covered as 1+1+3=5.
coverage
5 is covered.
1,4 are covered as 1+4=5.
2,3 are covered as 2+3=5.
Goal:
For given array A and integer K, find all possible "coverages". I need all coverages, not only one which covers most of the array items.
I have tried with two approaches:
Brut force algorithm.
Checking all possible subsets of all possible sizes works, but takes too much time even for only 10 numbers. I need it to finish in no more than 500ms.
First, I sorted the array in descending order. Then for each possible number of sub-sums I create "slots". I loop through the array and put numbers in the slots following the rules like:
Put number in the slot if its sum becomes equal to K.
Put number in the slot having the least sum of all slots.
Put number in the slot which gives the closet sum to K of all slots.
Well, the second approach works and works fast. But I found scenarios where some coverages are not found.
I would appreciate if somebody offered idea for solving this problem.
I hope I explained the problem well.
Thanks.
I don't have ready answer for that, but I recommend to take a look on 'Bin packing problem' it could be usefull here.
The main problem is to find all possible sums giving number K. So try this:
Collection All_Possible_Sums_GivingK;
find_All_Sums_Equal_To_K(Integer K, Array A)
{
/* this function after finding result
add it to global Collection AllPossibleSumsGivingK; */
find_All_Elements_Equal_To_K(Integer K, Array A);
Array B = Remove_Elements_Geater_Or_Equal_To_K(Integer K, Array A);
for all a in A {
find_All_Sums_Equal_To_K(Integer K-a, Array B-a)
}
}
I modified this from an earlier answer I gave to a different subset sum variant: https://stackoverflow.com/a/10612601/120169
I am running it here on the K=8 case with the above numbers, where we reuse 1 in two different places for one of the two "coverages". Let me know how it works for you.
public class TurboAdder2 {
// Problem inputs
// The unique values
private static final int[] data = new int[] { 1, 2, 3, 4, 5 };
// counts[i] = the number of copies of i
private static final int[] counts = new int[] { 2, 1, 1, 1, 1 };
// The sum we want to achieve
private static int target = 8;
private static class Node {
public final int index;
public final int count;
public final Node prevInList;
public final int prevSum;
public Node(int index, int count, Node prevInList, int prevSum) {
this.index = index;
this.count = count;
this.prevInList = prevInList;
this.prevSum = prevSum;
}
}
private static Node sums[] = new Node[target+1];
// Only for use by printString and isSolvable.
private static int forbiddenValues[] = new int[data.length];
private static boolean isSolvable(Node n) {
if (n == null) {
return true;
} else {
while (n != null) {
int idx = n.index;
// We prevent recursion on a value already seen.
// Don't use any indexes smaller than lastIdx
if (forbiddenValues[idx] + n.count <= counts[idx]) {
// Verify that none of the bigger indexes are set
forbiddenValues[idx] += n.count;
boolean ret = isSolvable(sums[n.prevSum]);
forbiddenValues[idx] -= n.count;
if (ret) {
return true;
}
}
n = n.prevInList;
}
return false;
}
}
public static void printString(String prev, Node n, int firstIdx, int lastIdx) {
if (n == null) {
printString(prev +" |", sums[target], -1, firstIdx);
} else {
if (firstIdx == -1 && !isSolvable(sums[target])) {
int lidx = prev.lastIndexOf("|");
if (lidx != -1) {
System.out.println(prev.substring(0, lidx));
}
}
else {
while (n != null) {
int idx = n.index;
// We prevent recursion on a value already seen.
// Don't use any indexes larger than lastIdx
if (forbiddenValues[idx] + n.count <= counts[idx] && (lastIdx < 0 || idx < lastIdx)) {
// Verify that none of the bigger indexes are set
forbiddenValues[idx] += n.count;
printString((prev == null ? "" : (prev + (prev.charAt(prev.length()-1) == '|' ? " " : " + ")))+data[idx]+"*"+n.count, sums[n.prevSum], (firstIdx == -1 ? idx : firstIdx), idx);
forbiddenValues[idx] -= n.count;
}
n = n.prevInList;
}
}
}
}
public static void main(String[] args) {
for (int i = 0; i < data.length; i++) {
int value = data[i];
for (int count = 1, sum = value; count <= counts[i] && sum <= target; count++, sum += value) {
for (int newsum = sum+1; newsum <= target; newsum++) {
if (sums[newsum - sum] != null) {
sums[newsum] = new Node(i, count, sums[newsum], newsum - sum);
}
}
}
for (int count = 1, sum = value; count <= counts[i] && sum <= target; count++, sum += value) {
sums[sum] = new Node(i, count, sums[sum], 0);
}
}
printString(null, sums[target], -1, -1);
}
}
I am thinking about this topcoder problem.
Given a string of digits, find the minimum number of additions required for the string to equal some target number. Each addition is the equivalent of inserting a plus sign somewhere into the string of digits. After all plus signs are inserted, evaluate the sum as usual.
For example, consider "303" and a target sum of 6. The best strategy is "3+03".
I would solve it with brute force as follows:
for each i in 0 to 9 // i -- number of plus signs to insert
for each combination c of i from 10
for each pos in c // we can just split the string w/o inserting plus signs
insert plus sign in position pos
evaluate the expression
if the expression value == given sum
return i
Does it make sense? Is it optimal from the performance point of view?
...
Well, now I see that a dynamic programming solution will be more efficient. However it is interesting if the presented solution makes sense anyway.
It's certainly not optimal. If, for example, you are given the string "1234567890" and the target is a three-digit number, you know that you have to split the string into at least four parts, so you need not check 0, 1, or 2 inserts. Also, the target limits the range of admissible insertion positions. Both points have small impact for short strings, but can make a huge difference for longer ones. However, I suspect there's a vastly better method, smells a bit of DP.
I haven't given it much thought yet, but if you scroll down you can see a link to the contest it was from, and from there you can see the solvers' solutions. Here's one in C#.
using System;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections;
public class QuickSums {
public int minSums(string numbers, int sum) {
int[] arr = new int[numbers.Length];
for (int i = 0 ; i < arr.Length; i++)
arr[i] = 0;
int min = 15;
while (arr[arr.Length - 1] != 2)
{
arr[0]++;
for (int i = 0; i < arr.Length - 1; i++)
if (arr[i] == 2)
{
arr[i] = 0;
arr[i + 1]++;
}
String newString = "";
for (int i = 0; i < numbers.Length; i++)
{
newString+=numbers[i];
if (arr[i] == 1)
newString+="+";
}
String[] nums = newString.Split('+');
int sum1 = 0;
for (int i = 0; i < nums.Length; i++)
try
{
sum1 += Int32.Parse(nums[i]);
}
catch
{
}
if (sum == sum1 && nums.Length - 1 < min)
min = nums.Length - 1;
}
if (min == 15)
return -1;
return min;
}
}
Because input length is small (10) all possible ways (which can be found by a simple binary counter of length 10) is small (2^10 = 1024), so your algorithm is fast enough and returns valid result, and IMO there is no need to improve it.
In all until your solution works fine in time and memory and other given constrains, there is no need to do micro optimization. e.g this case as akappa offered can be solved with DP like DP in two-Partition problem, but when your algorithm is fast there is no need to do this and may be adding some big constant or making code unreadable.
I just offer parse digits of string one time (in array of length 10) to prevent from too many string parsing, and just use a*10^k + ... (Also you can calculate 10^k for k=0..9 in startup and save its value).
I think the problem is similar to Matrix Chain Multiplication problem where we have to put braces for least multiplication. Here braces represent '+'. So I think it could be solved by similar dp approach.. Will try to implement it.
dynamic programming :
public class QuickSums {
public static int req(int n, int[] digits, int sum) {
if (n == 0) {
if (sum == 0)
return 0;
else
return -1;
} else if (n == 1) {
if (sum == digits[0]) {
return 0;
} else {
return -1;
}
}
int deg = 1;
int red = 0;
int opt = 100000;
int split = -1;
for (int i=0; i<n;i++) {
red += digits[n-i-1] * deg;
int t = req(n-i-1,digits,sum - red);
if (t != -1 && t <= opt) {
opt = t;
split = i;
}
deg = deg*10;
}
if (opt == 100000)
return -1;
if (split == n-1)
return opt;
else
return opt + 1;
}
public static int solve (String digits,int sum) {
int [] dig = new int[digits.length()];
for (int i=0;i<digits.length();i++) {
dig[i] = digits.charAt(i) - 48;
}
return req(digits.length(), dig, sum);
}
public static void doit() {
String digits = "9230560001";
int sum = 71;
int result = solve(digits, sum);
System.out.println(result);
}
Seems to be too late .. but just read some comments and answers here which say no to dp approach . But it is a very straightforward dp similar to rod-cutting problem:
To get the essence:
int val[N][N];
int dp[N][T];
val[i][j]: numerical value of s[i..j] including both i and j
val[i][j] can be easily computed using dynamic programming approach in O(N^2) time
dp[i][j] : Minimum no of '+' symbols to be inserted in s[0..i] to get the required sum j
dp[i][j] = min( 1+dp[k][j-val[k+1][j]] ) over all k such that 0<=k<=i and val[k][j]>0
In simple terms , to compute dp[i][j] you assume the position k of last '+' symbol and then recur for s[0..k]