Find the minimum number of cuts - java

Can anybody give me a hint how to find efficient solution for the problem below?
Alex brought a roll to the kitchen, which he wants to share with his colleagues. To do this, he wants to cut the roll into N equal parts. Of course, the roll can only be cut across. Accordingly, Alex will make N − 1 cut with a knife at regular intervals.
Upon returning from the coffee break, Alex wondered - could it be possible to do with fewer movements, if Vanya's knife was infinitely long (in other words, if he could make as many cuts as he wanted at a time, if these cuts lie on one straight line)? It is believed that the places for the cuts are planned in advance, and all cuts are made with pinpoint precision.
It turns out that you can. For example, if Alex would like to divide the roll into 4 parts, he could do with two cuts - first he would divide the roll into two halves, and then combine the two halves and cut both in half at the same time. So I need to find the minimum of cuts.
Given N - people
6
Result
3
Given N - people
5
Result
3
I can do it with a small number of people, but what if there 100 or 1000 people?
My code below:
public class Cake{
public static void main(String[] args) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
int number = Integer.parseInt(reader.readLine());
int all = 0;
if (N % 2 == 0) {
all = number/ 2;
}
else {
all = number / 2 + 1;
}
System.out.println(all);
}
}

It is indeed a math problem. You will need log(N,2) cuts for the first power of 2 people and one more for the extra people.
from math import log
def cutCount(N): return 0 if N<2 else int(log(N-1,2))+1
output:
for N in range(1,10): print(N,"people, cuts: ",cutCount(N))
1 people, cuts: 0
2 people, cuts: 1
3 people, cuts: 2
4 people, cuts: 2
5 people, cuts: 3
6 people, cuts: 3
7 people, cuts: 3
8 people, cuts: 3
9 people, cuts: 4
To verify for larger numbers, you can simulate the cuts mentally:
cutCount(50) # 6
1st cut --> 2 pieces
2nd cut --> 4 pieces
3rd cut --> 8 pieces
4th cut --> 16 pieces
5th cut --> 32 pieces
6th cut --> only cut 18 of the 32 pieces --> 50 pieces
Assuming you placed the pieces strategically every time, the last 18 pieces you need to cut are exactly 2/50th of the total length and the 14 others are 1/50th
there are several ways to do the "strategic" cuts. Here's an example:
Number x Lengths (in 1/50th of the total length):
cut #1 : [-----1x32-----][------------1x18---------------] total 2 pieces
cut #2 : [-----2x16-----][------------2x9----------------] total 4 pieces
cut #3 : [------4x8-----][---2x4--][--------2x5----------] total 8 pieces
cut #4 : [------8x4-----][---4x2--][--2x2--][----2x3-----] total 16 pieces
cut #5 : [-----16x2-----](------12x1-------)(-2x1-)[-2x2-] total 32 pieces
(----------14x1--------)[--------18x2-----------]
cut #6 : (----------14x1--------)(--------32x1-----------) total 50 pieces
(---------------------50x1----------------------)
Brackets are not to scale. Pieces that are 1/50th are not cut any further
If you want a recursive version of this calculation, you can count 1 for every time you are able to divide the number of people by 2 and then add 1 if there was at least one odd result in these divisions:
def cutCount(N,odd=0):
return odd if N<2 else 1+cutCount(N//2,odd|N%2)

Using Recursive algorithm
Note: Alain T answer is exact formula
Code
def cuts(n):
'''
Recursively decide number of required cuts '
Algorithm:
Base case: n = 0 or 1:
no cuts, so answer is 0
n is even: divide roll into two rolls of n//2 (1 cut).
These two rolls can be cut in parallel in the future
so cuts will be 1 + cuts(n//2).
Since n is even, n//2 == (n+1)//2,
so this can also be written as 1 + cuts((n+1)//2).
So answer is: 1 + cuts((n+1)//2)
Odd n: divide roll into two rolls of lengths n//2 and (n+1)//2 (1 cut)
One of these is even, the other odd.
These two rolls can be cut in parallel successively
until the longer 1 is reduced to length 1.
Thus cuts is 1 + cuts(max((n//2), (n+1)//2))
For all n: (n+1)//2 >= (n//2), so
max((n//2), (n+1)//2) = (n+1)//2
So answer is 1 + cuts((n+1)//2)
So we have:
if n = 0 or 1: return 0
otherwise: return 1 + cuts((n+1)//2)
'''
return 0 if n < 2 else 1 + cuts((n+1)//2)
for n in list(range(9)) + [20, 50, 100, 1000, 10000]:
print(f'{n} people, cuts: {cuts(n)}')
Output
0 people, cuts: 0
1 people, cuts: 0
2 people, cuts: 1
3 people, cuts: 2
4 people, cuts: 2
5 people, cuts: 3
6 people, cuts: 3
7 people, cuts: 3
8 people, cuts: 3
20 people, cuts: 5
50 people, cuts: 6
100 people, cuts: 7
1000 people, cuts: 10
10000 people, cuts: 14

Related

Backtracking chopsticks in java

I have an exercise that is killing my brain; which is:
I have x sticks, and I break them into x chunks which I measure, they are a vector of numbers, the solution to the problem is to find the minimum number to create sticks of the same size:
Sample input
9
5 2 1 5 2 1 5 2 1
4
1 2 3 4
0 (this is the end of the input it have to be there)
Sample output
6
5

How to calculate time needed through multiple routes?

For example, with input like:
4 6 7
1 2 6 2
......//more routes statement same format as second line
1 4
It means there are 4 places in total, and 6 routes in total, with 7cm convex hull of the ship(From the first line). The next 6 lines states where does the route connect, time needed and how many cm of the hull were worn down in the process. (In the second line, the route connects 1 and , takes 6 minutes, and wore down the hull by 2. The last line states where the starting point and destination are (1 and 4 in this case). The goal for this program is to get the minimum time used with the hull not completely worn down. I had tried using a
map(starting point of a route, end point);
but I can't really assign time used or the number of hull worn down this way, since multiple route can have the same starting point, meaning the two locations can't be used as a key like
map(starting point, time);
Also
Matrix[boolean][boolean]
doesn't seem to be an effective way to do this question. What technique should I use for this program and how do I do it?
Complete example with input:
10 4 7
1 2 4 4
1 3 7 2
3 1 8 1
3 2 2 2
4 2 1 6
3 4 1 1
1 4 6 12
1 4
output:
7
The routes can be used in two directions.

Limit Rows in Result Set By Column Values

This question deals with building a correct Criteria in Hibernate for the following case.
Suppose I start with a table like this:
id ts metric value carrier
1 1 distance 4 alice
2 1 count 2 alice
3 2 distance 3 alice
4 2 count 1 alice
5 1 distance 3 becky
6 1 count 2 becky
7 2 distance 4 becky
8 2 count 1 becky
9 1 distance 10 other
10 1 count 10 other
11 2 distance 10 other
12 2 distance 10 other
What this is is a time-bucketed set of metrics recording how far alice, becky and a general other carried some count of items some distance.
I'd like to roll it up in the following fashion: metrics with 'other' or the 'winner' as decided by distance for each time bucket are kept. Thus, the above table would yield the following result set:
id ts metric value carrier
1 1 distance 4 alice
2 1 count 2 alice
7 2 distance 4 becky
8 2 count 1 becky
9 1 distance 10 other
10 1 count 10 other
11 2 distance 10 other
12 2 distance 10 other
Ultimately this is translated to this:
ts carrier distance count
1 alice 4 2
1 other 10 10
2 becky 4 1
2 other 10 10
But this translation I already understand how to do. What I'm unclear on is how to build the criteria to keep the 'top n' metrics. Which brings us to the wrinkle: while this example is simplified, there would be a large number of 'carriers', and what I'm interested in is the top n such carriers, discarding the rest. Thus in the example above n = 1, but it's likely to be greater than 1 in most cases.
I know that I can use addOrder(Order.desc("value"), but that poses both a problem in that other is intermixed and distances and counts will be incorrectly intermingled. I'm looking for something that sorts 'blocks' of rows which are decided, in order by ts, then carrier, then using the metric = "distance" for the sort order.

Dynamic Programing to generate combinations

I had a technical phone interview and I was doing well until i was asked this question. I was totally lost i had very little idea on how to solve such a problem.
You are given the following inputs: Total Score, Number of Players, Scores by each player. Sample Input would be
10 4 3 5 5 7
Where
10 = Total Score
4 = 4 players
3 = Score by player 1
5 = Score by player 2
5 = Score by player 3
7 = Score by player 4
You are to print out any combination that equals the total score. For instance we know player 4 and player 1 can have combine score of total score 10. So output for the above answer would be
1 4
1 = INDEX of player 1 4 = INDEX of player 4. Yes i know index of player 1 is technically 0 but they said print it out as such. If no combination matched you can print out none or anything you like . That didn't matter.
MY ATTEMPT
Well rather than being silent i first told interviewer i can use brute force approach to solve this. He said of course but we need better run time.
So i started thinking we could find all the possible combinations that could lead the total dollar and use MEMOIZATION to store the previously stored values. I was not able to think of a way of generating all combos and so i got stuck there.
Update
He also mentioned the maximum score i can give you is 1000. I am not even sure why this matters?
I would appreciate if someone can stir me in right direction or even provide pseudo/working java sample of how to solve such a problem. I think this is a generic problem and i really wanna understand how to solve this problem
This is the subset sum problem, and assuming your scores are relatively small integers, it can be solved in pseudo-polynomial time using DP:
D(i,0) = 1
D(0,x) = 0 x > 0
D(i,x) = D(i-1, x) + D(i-1, x-arr[i])
The above recursion formulas will generate the matrix of size total_score X num_players. The number of possible combination is denoted in the bottom right entry of the matrix.
The idea is to mimic an exhaustive search, for each person you can either add it or not add it, and invoke the recurse to a smaller problem.
Pseudo code for DP solution:
Input:
let W be the total score
let arr be the array of players scores
let n be the size of arr
Pseudo Code:
declare 2d array D of size W+1 X n+1
//initialization of "borders":
for each i from 0 to n+1:
D[i][0] = 1
for each x from 1 to W+1
D[0][x] = 0
//the DP:
for each i from 1 to n+1:
for each x from 1 to W+1:
if arr[i] < x:
D[i][x] = D[i-1][x]
else:
D[i][x] = D[i-1][x] + D[i-1][x-arr[i]]
//by here you have the matrix D filled up
//the wanted value is D[n][W]
return D[n][W]

Random class acting odd?

In this code:
Random random = new Random(441287210);
for(int i=0;i<10;i++)
System.out.print(random.nextInt(10)+" ");
}
The output is 1 1 1 1 1 1 1 1 1 1, every time.
Why is this? Isn't Random supposed to be... well... random? I thought that the Random class use System.nanoTime, so the output should be generally random. Can someone please explain?
Let it print a couple more, the first 100 are
1 1 1 1 1 1 1 1 1 1 3 4 7 2 2 6 0 3 0 2 8 4 1 6 0 0 0 2 8 2 9 8 9 2 5 2 1 1 4 5 3 4 1 4 1
8 7 6 6 0 6 5 0 4 5 5 6 0 8 3 8 9 7 4 0 9 9 7 7 9 3 9 6 4 5 0 6 3 7 4 9 8 7 6 2 8 9 8 4 4
8 4 9 0 1 6 9 6 1 5
which looks okay.
Every good (pseudo) random sequence contains streaks of repeated numbers, this one begins with one.
The values generated by Random class are pseudo-random: they are created using a deterministic algorithm, based on seed value. Typically (if you use parameterless constructor, for example) the seed is initialized using current time, which is obviously a unique value. Hence a unique, 'random' sequence is generated.
Here you are using a constant seed value which doesn't change between executions of your code. Therefore you always get the same sequence. It just happens that this sequence is 1 1 1 1 1 1 ... for this particular seed.
There's nothing to say that a sequence of 10 1s in a row is not possible. Whoever gave you the seed value 441287210 just happens to have found such a value that results in starting with 10 1s in a row. If you continue calling nextInt() (i.e. more than 10 times) you will see random values. It should be possible to find other seed values that will result in other "apparently non-random" sequences.
Random is a linear congruential generator; i.e. it is based on a formula of the form:
N <- (N * C1 + C2) % M
where C1, C2 and M are constants.
One of the properties of this class of generator is that has high auto-correlation. Indeed, if you plot successive numbers you can see clear stripping patterns in the numbers.
Your test program has effectively taken 10 successive numbers from the underlying generator, calculated their value modulo 10 ... and found that they are all the same. Effectively, the modulo 10 is "resonating" with the natural periodicity of the generator ... over a short period of time.
This is one of the downsides of using a PRNG with high auto-correlation. In layman's terms ... it is "not very random" ... and you can get into trouble if you use it in a situation where randomness is critical.
Notes:
Random is not a random number generator. It is a pseudo-random number generator. That means that if you know the initial state, the numbers generated are entirely predictable.
Using a true random seed for Random doesn't really help. It just makes the problem harder to reproduce.
There are likely to be other seeds for Random that will give you similar patterns with this particular test.
From a purely mathematical standpoint, ten ones is no more or less "random" than any other sequence of ten numbers. But from a mathematical perspective, Random is not random at all. In fact, it is totally predictable once you have figured out what the current value of N is. The problem is the auto-correlation that is making the sequence appear intuitively non-random.
If you want to avoid this kind of intuitive non-randomness, use SecureRandom which should either be a true random number source, or a generator of pseudo-random numbers that are much, much harder to predict.
If you use for(int i=0;i<100;i++), the sequence outputted is "more random" again. The probability of a random sequence of ten 1s in succession occuring might be small, but it's not impossible. (Insofar that given enough samples, any sequence is almost certain to occur.)
It's merely an interesting coincidence.
Random class uses seed to generate random number when you call nextInt() and is advised to be a long number, when you are creating random object, you are providing an int which is not sufficient enough for randomness.
Try to run the loop for 20 times, you will see randomness or remove seed or provide a very long seed value

Categories

Resources