This question already has answers here:
How to find which elements are in the bag, using Knapsack Algorithm [and not only the bag's value]?
(4 answers)
Closed 2 years ago.
I know how to solve knapsack 0-1 problem with dynamic programming approach, but I am having troubles figuring out which items to take without compromising the complexity of O(N * C) (N items, C capacity).
Any ideas (I would prefer a bottom-up approach)?
Suppose, right now you're storing results in array bool[] a, where a[i] is true when sum i can be achieved.
You'll need another array int[] b, where b[i] is a last element you've placed into knapsack to achieve sum i.
So, where you had
a[i] = true;
you'll need
a[i] = true;
b[i] = current_item;
Then, finding which items can be taken to achieve sum i is a simple loop.
PS I use two arrays for simplicity, but obviously array a can be removed.
Here is a modification to reconstruct path in O(n) times
int knapsack(int weight[], int profit[], int no_of_items, int capacity) {
for (int var = 0; var <= capacity; ++var) {
dp[0][var] = 0;
}
for (int var = 0; var <= no_of_items; ++var) {
path[var] = false;
}
int using_item_i, without_using_item_i;
for (int i = 1; i <= no_of_items; ++i) {
for (int j = 1; j <= capacity; ++j) {
without_using_item_i = dp[i - 1][j];
using_item_i = 0;
if ((weight[i]) <= j) {
using_item_i = dp[i - 1][j - weight[i]] + profit[i];
}
if (using_item_i >= without_using_item_i) {
taken[i][j] = true;
dp[i][j] = using_item_i;
} else {
taken[i][j] = false;
dp[i][j] = without_using_item_i;
}
}
}
//Reconstructing back the path
int j = capacity;
for (int i = no_of_items; i >= 0; --i) {
if (taken[i][j]) {
path[i] = true;
cnt++;
}
j = j - weight[i];
}
return dp[no_of_items][capacity];
}
boolean[] solution = new boolean[nItems];
for (int i = nItems, c = maxCapacity; i > 0 && c > 0; i--) {
int iThItemAddedValue = value[i - 1][c - weights[i - 1]] + values[i - 1];
int iThItemInheritedValue = value[i - 1][c];
if (iThItemAddedValue > iThItemInheritedValue) {
solution[i - 1] = true;
c = c - weights[i - 1];
} else {
solution[i - 1] = false;
}
}
Check the sol in the attached image
public class Knapsackproblem {
private static int[][] cache;
public static void main(String[] args) {
int val[] = new int[]{60, 100, 120};
int wt[] = new int[]{10, 20, 30};
int W = 50;
int n = val.length;
System.out.println(knapSack(W, wt, val, n));
printValues(wt,val);
}
/**
* This method will find the result with
* more value with weight less than or equal
* to given weight
* #param w given weight
* #param wt arrays of weights
* #param val array of values
* #param n length of the array
* #return max value we can obtain
*/
private static int knapSack(int w, int[] wt, int[] val, int n) {
cache = new int[n+1][w+1];
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= w; j++) {
if(j < wt[i-1]){
cache[i][j] = cache[i-1][j];
}else {
cache[i][j] = Math.max(cache[i-1][j],(cache[i-1][j-wt[i-1]])+val[i-1]);
}
}
}
for (int[] aCache : cache) {
System.out.println(Arrays.toString(aCache));
}
return cache[n][w];
}
private static void printValues(int[] wt, int[] val) {
int m = cache.length-1;
int n = cache[0].length-1;
util(wt,val,m,n);
}
private static void util(int[] wt, int[] val, int m, int n) {
if(m <=0 || n<=0) return;
if((cache[m][n] != cache[m-1][n]) && (cache[m][n] != cache[m][n-1])){
System.out.println(val[m-1]+"-->"+wt[m-1]);
util(wt, val, m-1, (n - wt[m - 1] + 1));
}else
if(cache[m][n] == cache[m-1][n]){
util(wt,val,m-1,n);
}
else if(cache[m][n] == cache[m][n-1])
util(wt,val,m,n-1);
else
util(wt,val,m,(n-val[m-1]+1));
}
}
https://www.dropbox.com/s/ish7t5vgy91fovt/Screenshot%202017-01-01%2015.16.31.png?dl=0
Print the tmpList in the caller and you will get the answer
Related
Given an array and some value X, find the number of pairs such that i < j , a[i] = a[j] and (i * j) % X == 0
Array size <= 10^5
I am thinking of this problem for a while but only could come up with the brute force solution(by checking all pairs) which will obviously time-out [O(N^2) time complexity]
Any better approach?
First of all, store separate search structures for each distinct A[i] as we iterate.
i * j = k * X
i = k * X / j
Let X / j be some fraction. Since i is an integer, k would be of the form m * least_common_multiple(X, j) / X, where m is natural.
Example 1: j = 20, X = 60:
lcm(60, 20) = 60
matching `i`s would be of the form:
(m * 60 / 60) * 60 / 20
=> m * q, where q = 3
Example 2: j = 6, X = 2:
lcm(2, 6) = 6
matching `i`s would be of the form:
(m * 6 / 2) * 2 / 6
=> m * q, where q = 1
Next, I would consider how to efficiently query the number of multiples of a number in a sorted list of arbitrary naturals. One way is to hash the frequency of divisors of each i we add to the search structure of A[i]. But first consider i as j and add to the result the count of divisors q that already exist in the hash map.
JavaScript code with brute force testing at the end:
function gcd(a, b){
return b ? gcd(b, a % b) : a;
}
function getQ(X, j){
return X / gcd(X, j);
}
function addDivisors(n, map){
let m = 1;
while (m*m <= n){
if (n % m == 0){
map[m] = -~map[m];
const l = n / m;
if (l != m)
map[l] = -~map[l];
}
m += 1;
}
}
function f(A, X){
const Ais = {};
let result = 0;
for (let j=1; j<A.length; j++){
if (A[j] == A[0])
result += 1;
// Search
if (Ais.hasOwnProperty(A[j])){
const q = getQ(X, j);
result += Ais[A[j]][q] || 0;
// Initialise this value's
// search structure
} else {
Ais[A[j]] = {};
}
// Add divisors for j
addDivisors(j, Ais[A[j]]);
}
return result;
}
function bruteForce(A, X){
let result = 0;
for (let j=1; j<A.length; j++){
for (let i=0; i<j; i++){
if (A[i] == A[j] && (i*j % X) == 0)
result += 1;
}
}
return result;
}
var numTests = 1000;
var n = 100;
var m = 50;
var x = 100;
for (let i=0; i<numTests; i++){
const A = [];
for (let j=0; j<n; j++)
A.push(Math.ceil(Math.random() * m));
const X = Math.ceil(Math.random() * x);
const _brute = bruteForce(A, X);
const _f = f(A, X);
if (_brute != _f){
console.log("Mismatch!");
console.log(X, JSON.stringify(A));
console.log(_brute, _f);
break;
}
}
console.log("Done testing.")
Just in case If someone needed the java version of this answer - https://stackoverflow.com/a/69690416/19325755 explanation has been provided in that answer.
I spent lot of time in understanding the javascript code so I thought the people who are comfortable with java can refer this for better understanding.
import java.util.HashMap;
public class ThisProblem {
public static void main(String[] args) {
int t = 1000;
int n = 100;
int m = 50;
int x = 100;
for(int i = 0; i<t; i++) {
int[] A = new int[n];
for(int j = 0; j<n; j++) {
A[j] = ((int)Math.random()*m)+1;
}
int X = ((int)Math.random()*x)+1;
int optR = createMaps(A, X);
int brute = bruteForce(A, X);
if(optR != brute) {
System.out.println("Wrong Answer");
break;
}
}
System.out.println("Test Completed");
}
public static int bruteForce(int[] A, int X) {
int result = 0;
int n = A.length;
for(int i = 1; i<n; i++) {
for(int j = 0; j<i; j++) {
if(A[i] == A[j] && (i*j)%X == 0)
result++;
}
}
return result;
}
public static int gcd(int a, int b) {
return b==0 ? a : gcd(b, a%b);
}
public static int getQ(int X, int j) {
return X/gcd(X, j);
}
public static void addDivisors(int n, HashMap<Integer, Integer> map) {
int m = 1;
while(m*m <= n) {
if(n%m == 0) {
map.put(m, map.getOrDefault(m, 0)+1);
int l = n/m;
if(l != m) {
map.put(l, map.getOrDefault(l, 0)+1);
}
}
m++;
}
}
public static int createMaps(int[] A, int X) {
int result = 0;
HashMap<Integer, HashMap<Integer, Integer>> contentsOfA = new HashMap<>();
int n = A.length;
for(int i = 1; i<n; i++) {
if(A[i] == A[0])
result++;
if(contentsOfA.containsKey(A[i])) {
int q = getQ(X, i);
result += contentsOfA.get(A[i]).getOrDefault(q, 0);
} else {
contentsOfA.put(A[i], new HashMap<>());
}
addDivisors(i, contentsOfA.get(A[i]));
}
return result;
}
}
A set of integers is given as input. You have to return the subset of that set so that the mean - median is maximum for that subset.
Example 1
Input
{1,2,3,4}
Output
{1,2,4}
Example 2
Input
{1,2,2,3,3}
Output
{2,2,3}
package subsetMean_Median;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class MySolution {
public static void main(String[] args) {
int[] arr=
{2,3,2,1,3};
// {1,3,2,4};
Arrays.sort(arr);
int[] outp=meanMedian(arr);
for(int e:outp) {
System.out.print(e+"\t");
}
}
protected static int[] meanMedian(int[] arr) {
double median=findMedian(arr);
double mean=findMean(arr);
double diff=median-mean;
int MAXINDEX=0;
int n=arr.length;
double sets=(1<<n);
System.out.println("sets:"+sets);
for(int i=1;i<=sets;i++) {
int[] subset=findSubset(i,arr);
mean=findMean(subset);
median=findMedian(subset);
if(mean -median>diff) {
diff=mean-median;MAXINDEX=i;
}
}
System.out.println("mean: "+mean+"\tmedian: "+median+"\tdiff: "+diff);
return findSubset(MAXINDEX,arr);
}
protected static int[] findSubset(int counter, int[] arr) {
int n=arr.length;
List<Integer> ls=new ArrayList<Integer>();
for(int j=0;j<n;j++) {
if((counter & (1<<j))>0) {
ls.add(arr[j]);
}
}
int[] output= new int[ls.size()];
for(int j=0;j<ls.size();j++) {
output[j]=ls.get(j);
}
return output;
}
protected static double findMean(int[] arr) {
int n=arr.length;
double sum=0;
if(n==0) return 0;
for(int i=0;i<n;i++)
sum +=arr[i];
return (sum/n);
}
protected static double findMedian(int[] arr) {
int n=arr.length;
if(n%2==1)
return arr[(n/2)];
else if(n>=2)
return 0.5*(arr[((n-2)/2)]+arr[n/2]);
else return 0;
}
}
For every possible median:
lllllmrrrrr
Sort both parts L and R, then start choosing in pair lr maximal elements from both parts and with addition of every next element recompute mean, store arrangement with the best difference. Then the same for minimal elements.
There are about N possible medians, sorting takes O(N*lgN), on every iteration you need to compute up to N means, you can do it in O(N). So, overall complexity is O(N^3*LgN), but most likely you can avoid sorting on every iteration, instead sort whole array only once and update parts in O(1) on every iteration. With such an improvements it is O(N^2).
The most important thing in this problem is to find the Subset.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class MeanMedian {
public static void main(String[] args) {
int[] arr = { 1, 2, 3 };// { 1, 2, 2, 3, 3 };// { 1, 2, 3, 4 };
returnMaxMeanMedian(arr);
}
private static void returnMaxMeanMedian(int[] arr) {
double max = -999.9;
List<Integer[]> subArr = subSet(arr);
Integer[] maxArr = new Integer[1];
for (Integer[] sub : subArr) {
double newMax = calcDiff(sub);
if (max <= newMax) {
max = newMax;
maxArr = sub;
}
}
System.out.println(Arrays.toString(maxArr));
}
private static double calcDiff(Integer[] sub) {
// calc. mean
double sum = 0;
for (int i = 0; i < sub.length; i++) {
sum += sub[i];
}
sum = sum / sub.length;
// calc. median
double median = 0;
if (sub.length % 2 == 0)
median = (double) (sub[(sub.length / 2) - 1] + sub[sub.length / 2]) / 2;
else
median = sub[sub.length / 2];
double diff = sum - median;
return diff;
}
private static List<Integer[]> subSet(int[] arr) {
List<Integer[]> subArr = new ArrayList<Integer[]>();
int n = arr.length;
// Run a loop until 2^n
// subsets one by one
for (int i = 0; i < (1 << n); i++) {
String subSet = "";
// Print current subset
for (int j = 0; j < n; j++)
if ((i & (1 << j)) > 0)
subSet += arr[j] + " ";
subArr.add(convertToInt(subSet.trim().split(" ")));
}
return subArr;
}
private static Integer[] convertToInt(String[] arr) {
if (arr[0] == "")
return new Integer[] { 0 };
Integer[] intArr = new Integer[arr.length];
for (int i = 0; i < arr.length; i++) {
intArr[i] = Integer.parseInt(arr[i].trim());
}
return intArr;
}
}
Sort the list in O(n log n).
Deleting any element to the left of the median (center element or pair) has the same effect on the median, but affect the mean differently. Ditto for elements to the right.
That means that if anything will improve (mean - median), one of these will improve it the most:
the smallest element in the array
the smallest element to the right of the median
one of the element(s) that comprises the median
I.e., for each possible new median, how can we achieve the largest mean?
Repeatedly check these 3-4 for improving mean-median, deleting whatever improves the most. Each operation is O(1), as is recalculating the mean and median. You have to do this at most O(n) times.
The running time is O(n log n) if the list is unsorted, otherwise O(n).
Is this question only for a positive sequence of numbers? If yes, there's this efficient piece of code I wrote:
import java.util.Scanner;
public class MeanMedian {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc = new Scanner(System.in);
int i;
int j;
int k;
int in_length;
int mid_loc;
int sum_arr;
float median = 0.0f;
float mean = 0.0f;
float delta = 0.0f;
float incremental_delta = 0.0f;
float MEDIAN_FOR_MAX_DELTA = 0.0f;
float MEAN_FOR_MAX_DELTA = 0.0f;
float MAX_DELTA = -1.0f;
int MAX_SEQ_LENGTH = 0;
System.out.print("Enter the length of input: ");
in_length = sc.nextInt();
int in_arr[]= new int [in_length+1];
int out_arr[] = new int [in_length+1]; //This is the maximum size of the output array.
int MAX_DELTA_ARR[] = new int [in_length+1];
// STAGE-1: Accept the input sequence
for (i = 1; i <= in_length; i++) {
System.out.print("Enter the input #" + i + ": ");
in_arr[i] = sc.nextInt();
}
// STAGE-1 completed.
// STAGE-2: Sort the array (Bubble sort in Ascending order)
for (j = 1; j < in_length; j++) {
for (i = in_length; i > j; i--) {
if (in_arr[i-1] > in_arr[i]) {
k = in_arr[i];
in_arr[i] = in_arr[i-1];
in_arr[i-1] = k;
}
}
}
// STAGE-2 completed.
// STAGE-3: Compute Max Delta
MAX_DELTA = -99999; //Store as large -ve number as float data type can hold.
for (i = in_length; i > 2; i--) {
// STAGE-3a: Optional - Clear the out_arr[]
for (j = 1; j <= in_length; j++) {
out_arr [j] = 0;
}
// STAGE-3a completed.
// STAGE-3b: Determine the index of the median for the sequence of length i
if (i % 2 == 1) {
mid_loc = (i + 1)/2;
}
else {
mid_loc = (i / 2) + 1;
}
// STAGE-3b completed.
// STAGE-3c: Create the selection that gives the min median and max mean.
// STAGE-3c1: Create left side of mid point.
for (j = mid_loc; j > 0; j--) {
out_arr[j] = in_arr[j];
}
// STAGE-3c1 completed.
// STAGE-3c2: Create right side of mid point.
k = in_length;
for (j = i; j > mid_loc; j--) {
out_arr[j] = in_arr[k];
k = k - 1;
}
// STAGE-3c2 completed.
// STAGE-3c3: Do the SHIFT TEST.
//for (; k <= mid_loc + in_length - i; k++) {
for (k = mid_loc + 1; k <= mid_loc + in_length - i; k++) {
if (i % 2 == 1) {
incremental_delta = ((float)in_arr[k] - (float)out_arr[1])/i - ((float)in_arr[k] - (float)out_arr[mid_loc]);
}
else {
incremental_delta = ((float)in_arr[k] - (float)out_arr[1])/i - (((float)in_arr[k] - (float)out_arr[mid_loc]/2));
}
if (incremental_delta >= 0 ) {
//Insert this new element
for(j = 1; j < mid_loc; j++) {
out_arr[j] = out_arr[j+1];
}
out_arr[mid_loc] = in_arr[k];
}
}
// STAGE-3c3 completed.
// STAGE-3d: Find the median of the present sequence.
if(i % 2 == 1) {
median = out_arr[mid_loc];
}
else {
median = ((float)out_arr[mid_loc] + (float)out_arr[mid_loc - 1])/2;
}
// STAGE-3d completed.
// STAGE-3e: Find the mean of the present sequence.
sum_arr = 0;
for(j=1; j <= i ; j++) {
sum_arr = sum_arr + out_arr[j];
}
mean = (float)sum_arr / i;
// STAGE-3e completed.
// STAGE-3f: Find the delta for the present sequence and compare with previous MAX_DELTA. Store the result.
delta = mean - median;
if(delta > MAX_DELTA) {
MAX_DELTA = delta;
MEAN_FOR_MAX_DELTA = mean;
MEDIAN_FOR_MAX_DELTA = median;
MAX_SEQ_LENGTH = i;
for (j = 1; j <= MAX_SEQ_LENGTH; j++) {
MAX_DELTA_ARR[j] = out_arr[j];
}
}
// STAGE-3f completed.
}
// STAGE-4: Print the result.
System.out.println("--- RESULT ---");
System.out.print("The given input sequence is: ");
System.out.print("{ ");
for(i=1; i <= in_length; i++) {
System.out.print(in_arr[i]);
System.out.print(" ");
}
System.out.print("}");
System.out.println("");
System.out.print("The sequence with maximum difference between mean and median is: ");
System.out.print("{ ");
for(i=1; i <= MAX_SEQ_LENGTH; i++) {
System.out.print(MAX_DELTA_ARR[i]);
System.out.print(" ");
}
System.out.print("}");
System.out.println("");
System.out.println("The mean for this sequence is: " + MEAN_FOR_MAX_DELTA);
System.out.println("The median for this sequence is: " + MEDIAN_FOR_MAX_DELTA);
System.out.println("The maximum difference between mean and median for this sequence is: " + MAX_DELTA);
}
}
This code has order O(n) (if we ignore the necessity to sort the input array).
In case, -ve inputs are also expected - the only way out is by evaluating each subset. The downside to this approach is that the algorithm has exponential order: O(2^n).
As a compromise you could use both types of algorithm in your code and switch between the two by evaluating the input sequence. By the way, where did you come across this question?
from itertools import combinations
[Verfication of the code][1]
# function to generate all subsets possible, there will be 2^n - 1 subsets(combinations)
def subsets(arr):
temp = []
for i in range(1, len(arr)+1):
comb = combinations(arr, i)
for j in comb:
temp.append(j)
return temp
# function to calculate median
def median(arr):
mid = len(arr)//2
if(len(arr)%2==0):
median = (arr[mid] + arr[mid-1])/2
else:`
median = arr[mid]
return median
# function to calculate median
def mean(arr):
temp = 0
for i in arr:
temp = temp + i
return temp/len(arr)
# function to solve given problem
def meanMedian(arr):
sets = subsets(arr)
max_value = 0
for i in sets:
mean_median = mean(i)-median(i)
if(mean_median>max_value):
max_value = mean_median
needed_set = i
return needed_set
[1]: https://i.stack.imgur.com/Mx4pc.png
So I tried a little on the problem and here is a code that might help you. Its written in a way that should be easy to read, and if not, do let me know. Maybe you need to take array input from the user as I have taken a fixed array. That shouldn't be much of a problem I am sure.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
class MeanMinusMedian
{
private static float mean = 0;
private static float median = 0;
private static float meanMinusMedian = 0;
private static List<Integer> meanMinusMedianList = null;
private static void formMeanMinusMedianArr(int data[], int sumOfData)
{
findMean(data, sumOfData);
findMedian(data);
if ((mean - median) > meanMinusMedian) {
meanMinusMedian = mean - median;
meanMinusMedianList = new ArrayList<Integer>();
Arrays.stream(data)
.forEach(e->meanMinusMedianList.add(e));
}
}
/**
* #param data
*/
private static void findMedian(int[] data) {
int dataLen = data.length;
median = data.length % 2 == 0 ? ((float)data[dataLen / 2] + (float)data[dataLen / 2 - 1]) / 2 : data[dataLen / 2];
}
/**
* #param data
* #param sumOfData
*/
private static void findMean(int[] data, int sumOfData) {
mean = ((float)sumOfData /(float) data.length);
}
/**
*
* #param arr
* #param data
* #param start
* #param end
* #param index
* #param runningVal
*/
private static void combinationUtil(int arr[], int data[], int start, int end, int index, int runningVal) {
// Current combination is ready to be printed, print it
if (index == runningVal) {
formMeanMinusMedianArr(data, Arrays.stream(data) // Step 1
.sum());
return;
}
// replace index with all possible elements. The condition
// "end-i+1 >= r-index" makes sure that including one element
// at index will make a combination with remaining elements
// at remaining positions
for (int i = start; i <= end && end - i + 1 >= runningVal - index; i++) {
data[index] = arr[i];
combinationUtil(arr, data, i + 1, end, index + 1, runningVal);
}
}
/**
*
* #param arr
* #param n
* #param runningVal
*/
private static void printCombination(int arr[], int n, int runningVal) {
int data[] = new int[runningVal];
// Print all combination using temporary array 'data[]'
combinationUtil(arr, data, 0, n - 1, 0, runningVal);
}
public static void main(String[] args) {
int arr[] = { 1, 2, 2, 3, 3 };
int runningVal = 1;//Running value
int len = arr.length;
for (int i = 1; i < arr.length; i++) {
printCombination(arr, len, runningVal + i);
}
System.out.println(meanMinusMedianList);
}
}
Taking reference of answer of Bhaskar13 https://stackoverflow.com/a/59386801/3509609 , I solved it without using the bit shift operators, to add more readability.
package array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class MeanMinusMedianMax {
public static void main(String[] args) {
System.out.println(Arrays.toString(maxDiffrenceSubSet(4, new int[] { 4, 2, 3, 1 })));
System.out.println(Arrays.toString(maxDiffrenceSubSet(4, new int[] { 1, 2, 2, 3, 3 })));
}
public static int[] maxDiffrenceSubSet(int n, int[] input2) {
int totalSubsets = (int) Math.pow(2, n);
Map<Integer, ArrayList<Integer>> subsetsMap = new HashMap<Integer, ArrayList<Integer>>();
Integer maxKey = null;
double maxDiff = 0;
for (int i = 0; i < totalSubsets; i++) {
String binaryString = Integer.toBinaryString(i);
while (binaryString.length() < 4) {
binaryString = "0" + binaryString;
}
char[] currentPick = binaryString.toCharArray();
ArrayList<Integer> currentList = new ArrayList<Integer>();
for (int x = 0; x < currentPick.length; x++) {
if ((currentPick[x]) == '1') {
currentList.add(input2[x]);
}
}
Collections.sort(currentList);
subsetsMap.put(i, currentList);
double mean = findMean(currentList);
double median = findMedian(currentList);
double currentDifference = mean - median;
if (currentDifference > maxDiff) {
maxDiff = currentDifference;
maxKey = i;
}
}
return subsetsMap.get(maxKey).stream().mapToInt(i -> i).toArray();
}
static double findMean(ArrayList<Integer> arr) {
int n = arr.size();
double sum = 0;
if (n == 0)
return 0;
for (int i = 0; i < n; i++)
sum += arr.get(i);
return (sum / n);
}
static double findMedian(ArrayList<Integer> arr) {
int n = arr.size();
if (n % 2 == 1)
return arr.get((n / 2));
else if (n >= 2)
return 0.5 * (arr.get(((n - 2) / 2)) + arr.get(n / 2));
else
return 0;
}
}
class UserMainCode (object):
def meanmedian(cls,ip1,ip2=[]):
s = []
s = ip2
lst = []
final = []
op = []
max_val = 0
diff = 0
for i in range(1,ip1+1):
n=i
lst = list(itertools.combinations(s,n))
final = final +lst
for i in range(len(final)):
men = statistics.mean(final[i])
med = statistics.median(final[i])
diff = men - med
if max_val < diff:
op = final[i]
max_val = diff
return op
Find minimum cost of tickets required to buy for traveling on known days of the month (1...30). Three types of tickets are available : 1-day ticket valid for 1 days and costs 2 units, 7-days ticket valid for 7 days and costs 7 units, 30-days ticket valid for 30 days and costs 25 units.
For eg: I want to travel on [1,4,6,7,28,30] days of the month i.e. 1st, 4th, 6th ... day of the month. How to buy tickets so that the cost is minimum.
I tried to use dynamic programming to solve this but the solution is not giving me the correct answer for all cases. Here is my solution in Java :
public class TicketsCost {
public static void main(String args[]){
int[] arr = {1,5,6,9,28,30};
System.out.println(findMinCost(arr));
}
public static int findMinCost(int[] arr) {
int[][] dp = new int[arr.length][3];
int[] tDays = {1,7,30};
int[] tCost = {2,7,25};
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < 3; j++) {
if (j==0){
dp[i][j]= (i+1)*tCost[j];
}
else{
int c = arr[i]-tDays[j];
int tempCost = tCost[j];
int k;
if (c>=arr[0] && i>0){
for (k = i-1; k >= 0; k--) {
if (arr[k]<=c){
c = arr[k];
}
}
tempCost += dp[c][j];
int tempCostX = dp[i-1][j] + tCost[0];
tempCost = Math.min(tempCost,tempCostX);
}
dp[i][j] = Math.min(tempCost,dp[i][j-1]);
}
}
}
return dp[arr.length-1][2];
}
}
The solution doesn't work for {1,7,8,9,10} input, it gives 10 but the correct answer should be 9. Also, for {1,7,8,9,10,15} it give 13 but the correct is 11.
I have posted my solution not for other to debug it for me but just for reference. I was taken a bottom-up dynamic programming approach for this problem. Is this approach correct?
Let MC(d) denote the minimum cost that will pay for all trips on days 1 through d. The desired answer is then MC(30).
To calculate MC(d), observe the following:
If there's no trip on day d, then MC(d) = MC(d − 1).
As a special case, MC(d) = 0 for all d ≤ 0.
Otherwise, the minimum cost involves one of the following:
A 1-day pass on day d. In this case, MC(d) = MC(d − 1) + 2.
A 7-day pass ending on or after day d. In this case, MC(d) = min(MC(d − 7), MC(d − 6), …, MC(d − 1)) + 7.
And since MC is nondecreasing (adding a day never reduces the minimum cost), this can be simplified to MC(d) = MC(d − 7) + 7. (Hat-tip to Ravi for pointing this out.)
A 30-day pass covering the whole period. In this case, MC(d) = 25.
As you've realized, dynamic programming (bottom-up recursion) is well-suited to this.
For ease of coding, I suggest we start by converting the list of days into a lookup table for "is this a trip day?":
boolean[] isDayWithTrip = new boolean[31]; // note: initializes to false
for (final int dayWithTrip : arr) {
isDayWithTrip[dayWithTrip] = true;
}
We can then create an array to track the minimum costs, and populate it starting from index 0:
int[] minCostUpThroughDay = new int[31];
minCostUpThroughDay[0] = 0; // technically redundant
for (int d = 1; d <= 30; ++d) {
if (! isDayWithTrip[d]) {
minCostUpThroughDay[d] = minCostUpThroughDay[d-1];
continue;
}
int minCost;
// Possibility #1: one-day pass on day d:
minCost = minCostUpThroughDay[d-1] + 2;
// Possibility #2: seven-day pass ending on or after day d:
minCost =
Math.min(minCost, minCostUpThroughDay[Math.max(0, d-7)] + 7);
// Possibility #3: 30-day pass for the whole period:
minCost = Math.min(minCost, 25);
minCostUpThroughDay[d] = minCost;
}
And minCostUpThroughDay[30] is the result.
You can see the above code in action at: https://ideone.com/1Xx1fd.
One recursive solution in Python3.
from typing import List
def solution(A: List[int]) -> int:
if not any(A):
return 0
tickets = {
1: 2,
7: 7,
30: 25,
}
import sys
min_cost = sys.maxsize
size = len(A)
for length, price in tickets.items():
current_cost = price
idx = 0
last_day = A[idx] + length
while idx < size and A[idx] < last_day:
idx += 1
if current_cost > min_cost:
continue
current_cost += solution(A[idx:])
if current_cost < min_cost:
min_cost = current_cost
return min_cost
if __name__ == '__main__':
cases = {
11: [1, 4, 6, 7, 28, 30],
9: [1, 7, 8, 9, 10],
}
for expect, parameters in cases.items():
status = (expect == solution(parameters))
print("case pass status: %s, detail: %s == solution(%s)" %
(status, expect, parameters))
public class Main03v3
{
public static void main(String[] args)
{
int[] A = {1,7,8,9,10,15,16,17,18,21,25};
System.out.println("Traveling days:\r\n "+Arrays.toString(A));
int cost = solution(A);
System.out.println("\r\nMinimum cost is " + cost);
System.out.println("\r\n" + new String(new char[40]).replace("\0", "-"));
}
public static int solution(int[] A)
{
if (A == null) return -1;
int sevenDays = 7;
int dayCost = 2, weekCost = 7, monthCost = 25;
int ratio_WeekAndDays = weekCost / dayCost;
int len = A.length;
if (len == 0) return -1;
if (len <= 3) return len * dayCost;
int cost[] = new int[len];
int i = 0;
while (i < len)
{
int startIdx = i, endIdx = i + 1;
while (endIdx < len && A[endIdx]-A[startIdx] < sevenDays)
endIdx++;
if (endIdx-startIdx > ratio_WeekAndDays)
{
if (endIdx >= startIdx + sevenDays)
endIdx = startIdx + sevenDays;
int j = startIdx;
cost[j] = ((j == 0) ? 0 : cost[j-1]) + weekCost;
while (++j < endIdx) {
cost[j] = cost[j-1];
}
i = j;
}
else
{
cost[i] = ((i == 0) ? 0 : cost[i-1]) + dayCost;
i++;
}
}
int finalCost = Math.min(cost[len-1], monthCost);
return finalCost;
}
}
Find minimum cost of tickets in JavaScript
case 1 : if input is [1,7,8,9,10] then the required output is 9
case 2 : if input is [1,7,8,9,10,15] then the required output is 11
function calMinCosts(arr){
if(!arr || arr.length===0)
return 0;
var len = arr.length;
var costsOfDateArr = Array.apply(null,{length:arr[len-1]+1}).map(()=>0);
var price1=2,price2=7,price3=25;
var days=7;
var index=0,n=costsOfDateArr.length;
for(var i=1;i<n;i++){
if(i===arr[index]){
if(i>=days+1){
costsOfDateArr[i] = Math.min(costsOfDateArr[i-days-1]+price2, costsOfDateArr[i-1]+price1);
}else{
costsOfDateArr[i] = Math.min(costsOfDateArr[0]+price2, costsOfDateArr[i-1]+price1);
}
index+=1;
}else{
costsOfDateArr[i] = costsOfDateArr[i-1];
}
}
return Math.min(price3,costsOfDateArr[n-1]);
}
console.log(calMinCosts([1,7,8,9,10]))
console.log(calMinCosts([1,7,8,9,10,15]))
Here is the C++ solution including print outs
#include <vector>
#include <iostream>
#include <cmath>
#include <algorithm>
int compute(std::vector<int> &A)
{
int sum[A.size()][A.size()+1];
for (int i = 0; i < A.size(); i++)
{
for(int j =0; j < A.size(); j++)
{
sum[i][j]=2;
}
}
for (int k = 0; k < A.size();k++)
{
sum[k][A.size()]=0;
}
for (int i = 0; i < A.size(); i++)
{
for(int j = 0; j < A.size(); j++)
{
if (i!=j)
{
if (sum[i][i] != 7)
{
int temp = abs(A[j]-A[i]);
if (temp<7 && abs(j-i)>=3)
{
sum[i][i]=7;
sum[i][j]=7;
if (i>j)
{
for(int k = j;k < i;k++)
sum[i][k]=7;
}
else
{
for(int k = i;k < j;k++)
sum[i][k]=7;
}
}
}
}
}
}
for (int i = 0; i < A.size(); ++i)
{
for(int j = 0; j < A.size(); ++j)
{
if (sum[i][j]==7)
{
sum[i][A.size()]+=1;
}
}
}
for (int i = 0; i < A.size(); ++i)
{
for (int j = 0; j < A.size()+1; ++j)
std::cout<<sum[i][j]<<" ";
std::cout<<std::endl;
}
int result = 0;
int row = A.size()-1;
int column = A.size()-1;
while(1)
{
int value = sum[row][A.size()];
if (value == 0)
value=1;
int temp = sum[row][column];
result += temp;
row = row-value;
column = column-value;
while (sum[row][column+1]==7 && row>=0)
{
row-=1;
column-=1;
result+=2;
}
if (row < 0)
break;
}
return result;
}
int solution(std::vector<int> &A) {
if (A.size() > 24)
return 25;
if (A.size() <= 3)
return A.size() * 2;
return std::min(25,compute(A));
}
int main()
{
std::vector<int> AA={1,2,3,4,5,29,30};
std::vector<int> B={1,2,3,4,5};
std::vector<int> A={1,2,3,4,5,9,10,11,12,13,14,17,18,20,21};
std::vector<int> C={1,2,3,12};
std::vector<int> D={1,2,3,4,12,13,14,15,29,30};
std::vector<int> DD={1,2,3,4,5,14,17,18,19,20,23,28,29,30};
std::vector<int> CC={1,2,3,4,5,6,7,9,14,17,18,19,20,23,28,29,30};
std::cout<<solution(AA)<<std::endl;
std::cout<<solution(D)<<std::endl;
std::cout<<solution(B)<<std::endl;
std::cout<<solution(A)<<std::endl;
std::cout<<solution(C)<<std::endl;
std::cout<<solution(DD)<<std::endl;
std::cout<<solution(CC)<<std::endl;
return 0;
}
Solved using the same approach of bottom-up dynamic programming. Here is the full solution :
public class PublicTicketCost {
public static void main(String args[]){
int[] arr = {1,7,8,9,10,15,16,17,18,21,25};
int[] tDays = {1,7,30};
int[] tCost = {2,7,25};
System.out.println(minCost(arr, tDays, tCost));
}
public static int minCost(int[] arr, int[] tDays, int[] tCost) {
int[][] dp = new int[arr.length][tDays.length];
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < tDays.length; j++) {
int prevDayIndex = findPrevDayIndex(arr,i,tDays,j);
int prevCost = prevDayIndex>=0 ? dp[prevDayIndex][tDays.length-1] : 0;
int currCost = prevCost + tCost[j];
if(j-1>=0){
currCost = Math.min(currCost, dp[i][j-1]);
}
dp[i][j] = currCost;
}
}
//print(dp);
return dp[arr.length-1][tDays.length-1];
}
private static void print(int arr[][]){
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[0].length; j++) {
System.out.print(arr[i][j]+" ");
}
System.out.println();
}
}
private static int findPrevDayIndex(int[] arr, int i, int[] days, int j){
int validAfterDate = arr[i] - days[j];
if (validAfterDate<1){
return -1;
}
for (int k = i-1; k >= 0; k--) {
if (arr[k]<=validAfterDate){
return k;
}
}
return -1;
}
}
http://ideone.com/sfgxGo
I was wondering if there is an efficient premade algorithm for determining if the sum/difference of a group of numbers can equal a different number. Example:
5, 8, 10, 2, using + or -, to equal 9.
5 - 8 = -3 + 10 = 7 + 2 = 9
If there is a preexisting algorithm, what is it called. If not, I can figure out how to program it, though it may not be efficient.
Thank you!
Yeah, this is basically knapsack problem, but it can be computed in pseudopolynomial time using dynamic programming.
I did it few month ago, so maybe this java code can help you, if you want to implement it :
public void solve() {
while (this.isEnd() == false) {
int priceSum = this.getItemsInstance().getTotalPrice()/divide;
int numOfItems = this.getItemsInstance().itemCount();
int maxWeight = this.getItemsInstance().getMaxWeight();
int[][] array = new int[numOfItems + 1][priceSum + 1];
boolean[][] arrayCounted = new boolean[numOfItems + 1][priceSum + 1];
for (int i = 0; i < numOfItems + 1; i++) {
array[i][0] = 0;
arrayCounted[i][0] = true;
}
int max = 0;
int price = 0;
for (int j = 1; j < priceSum + 1; j++) {
for (int i = 1; i < numOfItems + 1; i++) {
int temp = W(i, j, array, arrayCounted);
if (temp <= maxWeight) {
max = temp;
price = j;
}
}
}
}
}
private int W(int i, int c, int[][] array, boolean[][] arrayCounted) {
if (c < 0) {
return MAX_PRICE / divide;
}
if (i == 0) {
if (c == 0) {
return 0;
} else {
return MAX_PRICE / divide;
}
}
if (arrayCounted[i][c]) {
return array[i][c];
}
arrayCounted[i][c] = true;
array[i][c] = Math.min(W(i - 1, c, array, arrayCounted), W(i - 1, c - this.items[i - 1].price/divide, array, arrayCounted) + this.items[i - 1].weight);
return array[i][c];
}
its not an NP problem, if the problem is to find a given number from adding or subtracting each elements of a list/array. if you think about AP. here is a sample code in C++
int Np( int mn, list<int>a, int c )
{
int size = a.size(), rst = 0, maxI = 0;
std::list<int>::iterator it;
while( size > c )
{
a.sort();
maxI += a.back();
a.pop_back();
rst = 0;
for( auto ele : a )
{
rst += ele;
cout << rst << endl;
}
if( (rst - maxI) == mn or (maxI - rst) == mn or (maxI + rst) == mn )
{
return mn;
}
size--;
}
return rst;
}
this should help. i think.
I actually wrote a simple java program, I was not actually aware of knapsack strategies. This is my own solution. Hope this helps
import java.util.ArrayList;
import java.util.List;
public class Puzzle {
public static void main(String[] args) {
int targetNumber = 0;
int min = 2147483647;
int[] numbers = {-10, -30, -20, -50};
//int[] numbers = {0,0,0,0};
//int[] numbers = {7, 2, 10};
//int[] numbers = {1, 2, 3, 4, 5};
//int[] numbers = {1000, 2, 3, 4, 100};
char set[] = {'+', '-'};
min = getNumberClosestToTarget(numbers, set, min, targetNumber);
System.out.println(String.format(" %d is closest to %d", min, targetNumber));
}
private static int getNumberClosestToTarget(int[] numbers, char[] set, int min, int targetNumber) {
List<String> operators = new ArrayList<>();
computeAllOperatorsCombination(set, "", set.length, numbers.length - 1, operators);
for (String operatorString : operators) {
String[] ops = operatorString.split("");
int sum = computeSum(numbers, ops, numbers.length - 1);
min = getClosestToTarget(min, targetNumber, sum);
}
return min;
}
static int computeSum(int[] numbers, String[] operators, int index) {
int result = numbers[index];
if (index == 0) {
return result;
} else {
switch (operators[index - 1]) {
case "+":
return computeSum(numbers, operators, index - 1) + result;
case "-":
return computeSum(numbers, operators, index - 1) - result;
}
return result;
}
}
static void computeAllOperatorsCombination(char set[], String prefix, int n, int k, List<String> result) {
if (k == 0) {
result.add(prefix);
return;
}
for (int i = 0; i < n; i++) {
String newPrefix;
newPrefix = prefix + set[i];
computeAllOperatorsCombination(set, newPrefix, n, k - 1, result);
}
}
private static int getClosestToTarget(int min, int targetNumber, int r) {
int distance = Math.abs(targetNumber - r) < Math.abs(r - targetNumber) ? Math.abs(targetNumber - r) : Math.abs(r - targetNumber);
if (distance < Math.abs(min)) {
min = distance;
if (r < 0) {
min = -distance;
}
}
return min;
}
}
There is array of values:
1 - n_1 times
2 - n_2 times
...
k - n_k times
How many trees with this nodes exist?
I create simple algorythm:
int get_count(const vector<int> n_i) {
if (n_i.size() <= 1) {
return 1;
} else {
int total_count = 0;
for (int i = 0; i < n_i.size(); ++i) {
vector<int> first;
vector<int> second;
for (int j = 0; j < i; ++j) {
first.push_back(n_i[j]);
}
if (n_i[i] != 1) {
second.push_back(n_i[i] - 1);
}
for (int j = i + 1; j < n_i.size(); ++j) {
second.push_back(n_i[j]);
}
total_count += (get_count(first) * get_count(second));
}
return total_count;
}
}
Because
#(n_1, n_2, ... n_k) = #(n_1 - 1, n_2, ..., n_k) + #(n_1) #(n_2 - 1, ... n_k) + ... + #(n_1, ..., n_k - 1)
and
#(0, n_i, n_j, ...) = #(n_i, n_j, ...)
But my code is so slow.
Is there a final formula via Cathalan's numbers, for example?
I guess that the problem can be split into calculating the number of permutations and calculating the number of binary trees of given size. I converted my initial recursive Java code (which gives up on n1=10,n2=10,n3=10) into this iterative one:
static int LIMIT = 1000;
static BigInteger[] numberOfBinaryTreesOfSize = numberOfBinaryTreesBelow(LIMIT);
static BigInteger[] numberOfBinaryTreesBelow(int m) {
BigInteger[] arr = new BigInteger[m];
arr[0] = BigInteger.ZERO;
arr[1] = arr[2] = BigInteger.ONE;
for (int n = 3; n < m; n++) {
BigInteger s = BigInteger.ZERO;
for (int i = 1; i < n; i++)
s = s.add(arr[i].multiply(arr[n - i]));
arr[n] = s;
}
return arr;
}
static BigInteger[] fac = facBelow(LIMIT);
static BigInteger[] facBelow(int m) {
BigInteger[] arr = new BigInteger[m];
arr[0] = arr[1] = BigInteger.ONE;
for (int i = 2; i < m; i++)
arr[i] = arr[i - 1].multiply(BigInteger.valueOf(i));
return arr;
}
static BigInteger getCountFast(int[] arr) {
// s: sum of n_i
int s = 0; for (int i = 0; i < arr.length; i++) { s += arr[i]; }
// p: number of permutations
BigInteger p = fac[s]; for (int i = 0; i < arr.length; i++) { p = p.divide(fac[arr[i]]); }
BigInteger count = p.multiply(numberOfBinaryTreesOfSize[s]);
return count;
}
public static void main(String[] args) {
System.out.println(getCountFast(new int[]{ 150, 150, 150, 150, 150 }));
}
The LIMIT limits the sum of the n_i. The above example takes about two seconds on my machine. Maybe it helps you with a C++ solution.