Dynamic Programming, sum of all 3 subarrays after bitwise xor them - java

I recently ran to a dynamic programming problem and I needed to solve it, so i couldn't figure it out myself so I started looking for solutions. The problem is:
There are N students in your class. The strength of each student is a small nonnegative integer.
You are
given these strengths in the int[] strength with N elements.
You are going to divide all students into three teams for the boat race "TrySail". Each student must be
assigned to exactly one of the three teams. Teams cannot be empty.
Strangely enough, in this race the strength of a team is the bitwise xor of the strengths of its members.
You want to maximize the sum of strengths of the three teams. Compute and return the largest possible
sum of the teams' strengths.
Constraints:
1) N will be between 3 and 50, inclusive.
2) strength will contain exactly N elements.
3)Each element of strength will be between 0 and 255, inclusive.
I found some solutions and specific this one. But i still don't know what happens here even when i debug it line per line. So if someone knows this problem or understands this and where and why he uses the variable sum and bitwise xor them (^) it would be really nice for some comments.
Here is the code:
public class TrySail
{
public int get(int[] strength)
{
var dp = new bool[256, 256];
dp[0, 0] = true;
var sum = 0;
foreach (var x in strength)
{
var next = new bool[256, 256];
for (int i = 0; i < 256; i++)
for (int j = 0; j < 256; j++)
{
if (!dp[i, j]) continue;
var rem = sum ^ i ^ j;
next[i ^ x, j] |= dp[i, j];
next[i, j ^ x] |= dp[i, j];
next[i, j] |= dp[i, j];
}
dp = next;
sum ^= x;
}
var max = 0;
for (int i = 0; i < 256; i++)
for (int j = 0; j < 256; j++)
{
if (!dp[i, j]) continue;
var rem = sum ^ i ^ j;
max = Math.Max(max, i + j + rem);
}
return max;
}
}
An example:
{7,3,5,2}
Returns: 17
There are 6 ways to make 3 teams:
· {0},{1},{2,3}: sum of strengths is 7+3+(5 xor 2) = 17
· {0},{2},{1,3}: sum of strengths is 7+5+(3 xor 2) = 13
· {0},{3},{1,2}: sum of strengths is 7+2+(3 xor 5) = 15
· {1},{2},{0,3}: sum of strengths is 3+5+(7 xor 2) = 13
· {1},{3},{0,2}: sum of strengths is 3+2+(7 xor 5) = 7
· {2},{3},{0,1}: sum of strengths is 5+2+(7 xor 3) = 11
Therefore, the answer is 17.
The code is written in C#

Related

How to add zeros to the end of value of Long object [duplicate]

for(i=0; i<array.length; i++){
sum = 4 * 5;
}
What I'm trying to do is add ((array.length - 1) - i) 0's to the value of sum. For this example assume array length is 3. sum equals 20. So for the first iteration of the loop i want to add ((3 - 1) - 0) 0's to the value of sum, so sum would be 2000. The next iteration would be ((3 - 1) - 1) 0's. so sum would equal 200 and so on. I hope what I am trying to achieve is clear.
So my questions are:
Is it possible to just shift an int to add extra digits? My search thus far suggests it is not.
If not, how can i achieve my desired goal?
Thankyou for reading my question and any help would be greatly apreciated.
You can just multiply it by 10 however many times.
200 * 10 = 2000
etc
So in your case, you'd have to use a for loop until the end of the array and multiply sum every iteration. Be careful though, because the max value of an int is 2^31, so it of surpasses that, it will roll back to 0
You can add n zeroes to the end of a number, sum by multiplying sum by 10 * n.
int sum = 20;
for (int i = 0; i < ary.length; ++i) {
int zeroesToAdd = ary.length - 1 - i
sum *= (zeroesToAdd > 0) ? zeroesToAdd * 10 : 1
}
System.out.println("Sum after loop: " + sum);
for(int i=array.length; i>0; i--){
sum = 20;
for(int j=0; j < (i - 1); j++)
{
sum *= 10;
}
}
Use inner loop to multiply by 10 the number of times i is for that iteration. You would need to reset sum in your outer loop each time.
You will want to check your for-loop condition: i>array.length. Since i starts at 0, this loop will not run unless the array's length is also 0 (an empty array). The correct condition is i < array.length.
This "shift" you want can be achieved by creating a temporary variable inside the loop that is equal to the sum times 10i. In Java's Math library, there is a pow(a,b) function that computes ab. With that in mind, what you want is something like this:
int oldSum = 4 * 5;
for (int i = 0; i < array.length; i++) {
int newSum = oldSum * Math.pow(10,i);
}
Multiply by 10 instead, and use < (not >) like
int sum = 20;
int[] array = { 1, 2, 3 };
for (int i = 0; i < array.length; i++) {
int powSum = sum;
for (int j = array.length - 1; j > i; j--) {
powSum *= 10;
}
System.out.println(powSum);
}
Output is (as requested)
2000
200
20
For array of length = n; you will end up adding (n - 1) + (n - 2) + ... + 2 + 1 + 0 zeros for i = 0, 1, ... n-2, n-1 respectively.
Therefore, number of zeros to append (z) = n * (n-1) / 2
So the answer is sum * (10 ^ z)
[EDIT]
The above can be used to find the answer after N iteration. (I miss read the question)
int n = array.length;
long sum = 20;
long pow = Math.pow(10, n-1); // for i = 0
for (int i = 0; i < n; i++) {
System.out.println(sum*pow);
pow /= 10;
}

Minimum number of substitutions to reach string: 01010101 ... 01 or 10101010 ... 10

Given a binary string, that is it contains only 0s and 1s (number of zeros equals the number of ones) We need to make this string a sequence of alternate characters by swapping some of the bits, our goal is to minimize the number swaps.
For example, for the string "00011011" the minimum number of swaps is 2, one way to do it is:
1) swap the bits : 00011011 --->> 00010111
2) swap the bits(after the first swap) : 00010111 --->> 01010101
Note that if we are given the string "00101011" we can turn it into an alternate string starting with 0 (that requires 3 swaps) and also into alternate string starting with 1 ( that requires one swap - the first and the last bits ).
So the minimum in this case is one swap.
The end goal is to return the minimum number of swaps for a given string of ones and zeros. What is the most efficient way to solve it?
What you are looking for is called the Levenshtein distance. It is a bit more complex since it works on all type of String not just bitstrings but based on the implementation you should be able to develop your own fitting solution. Here is an java implementation I found on Wikibooks:
public static int computeLevenshteinDistance(CharSequence lhs, CharSequence rhs) {
int[][] distance = new int[lhs.length() + 1][rhs.length() + 1];
for (int i = 0; i <= lhs.length(); i++)
distance[i][0] = i;
for (int j = 1; j <= rhs.length(); j++)
distance[0][j] = j;
for (int i = 1; i <= lhs.length(); i++)
for (int j = 1; j <= rhs.length(); j++)
distance[i][j] = minimum(
distance[i - 1][j] + 1,
distance[i][j - 1] + 1,
distance[i - 1][j - 1] + ((lhs.charAt(i - 1) == rhs.charAt(j - 1)) ? 0 : 1));
return distance[lhs.length()][rhs.length()];
}

Can anyone advise the idea of solving such a task without going through all subsets?

Ice-Cream:
The beach stretches along the seacoast like a narrow strip. At some points of the beach the ice cream stalls are located. One day not all the ice cream sellers come to work. Distribute the sellers among the ice-cream stalls so that the minimum distance between them is as much as possible. So they will interfere less with each other.
Input:
The first line contains the number of stalls n (2 < n < 10001) and the number of ice cream sellers k (1 < k < n) at work. The second line contains n positive integers in increasing order - the coordinates of the stalls (the coordinates are not greater than 109).
Output:
Print one number - the minimum distance between the adjacent stalls in the optimal arrangement.
Input example:
5 3
1 2 3 100 1000
Output example:
99
This is what I have come up with so far. It is working not fast enough and I need other idea.
import java.util.Scanner;
public class Main
{
public static void main(String[] args)
{
Scanner s = new Scanner(System.in);
int[] n = new int[s.nextInt()];
int k = s.nextInt();
for(int i = 0; i < n.length; i++)
{n[i] = s.nextInt();}
int c = -1;
int[] cA = new int[k + 3]; //control array
for(int j = 1; j < cA.length; j++)
{cA[j] = j - 1;}
cA[k+1] = n.length;
cA[k+2] = 0;
while(true)
{
int currentCoordinate = -1, previousCoordinate = -1, minDist = -1;
for(int i = 1; i <= k; i++)
{
if(currentCoordinate == -1)
{currentCoordinate = n[cA[i]];}
else
{
previousCoordinate = currentCoordinate;
currentCoordinate = n[cA[i]];
int currentDistance = currentCoordinate - previousCoordinate;
if(minDist == -1 || minDist > currentDistance)
{minDist = currentDistance;}
}
}
if(minDist > c)
{c = minDist;}
int j = 1;
while(cA[j] + 1 == cA[j + 1])
{cA[j] = j - 1; j++;}
if(j > k)
{break;}
cA[j] = cA[j] + 1;
}
System.out.println(c);
}
}
This problem is solvable using binary search. First assume the answer is x. It means the minimum distance between two stalls is x. A greedy approach can verify this assumption. It is obvious that in the best configuration we have to use the leftmost stall (Can be easily proven by contradiction). Now traverse the points from left to right until the distance between the leftmost point and the rightmost point is less than x. Upon reaching to the first point (pi) that its distance to the leftmost point is bigger than x increment your counter. From now on your leftmost is px. Repeat this process until you reach the end of the points. Now if your counter is bigger than k it means that you can increase the value of x and vice versa.
So you can binary search to find the minimum value for x. This approach is in O(nLogn).

Add 0's to the end of an integer

for(i=0; i<array.length; i++){
sum = 4 * 5;
}
What I'm trying to do is add ((array.length - 1) - i) 0's to the value of sum. For this example assume array length is 3. sum equals 20. So for the first iteration of the loop i want to add ((3 - 1) - 0) 0's to the value of sum, so sum would be 2000. The next iteration would be ((3 - 1) - 1) 0's. so sum would equal 200 and so on. I hope what I am trying to achieve is clear.
So my questions are:
Is it possible to just shift an int to add extra digits? My search thus far suggests it is not.
If not, how can i achieve my desired goal?
Thankyou for reading my question and any help would be greatly apreciated.
You can just multiply it by 10 however many times.
200 * 10 = 2000
etc
So in your case, you'd have to use a for loop until the end of the array and multiply sum every iteration. Be careful though, because the max value of an int is 2^31, so it of surpasses that, it will roll back to 0
You can add n zeroes to the end of a number, sum by multiplying sum by 10 * n.
int sum = 20;
for (int i = 0; i < ary.length; ++i) {
int zeroesToAdd = ary.length - 1 - i
sum *= (zeroesToAdd > 0) ? zeroesToAdd * 10 : 1
}
System.out.println("Sum after loop: " + sum);
for(int i=array.length; i>0; i--){
sum = 20;
for(int j=0; j < (i - 1); j++)
{
sum *= 10;
}
}
Use inner loop to multiply by 10 the number of times i is for that iteration. You would need to reset sum in your outer loop each time.
You will want to check your for-loop condition: i>array.length. Since i starts at 0, this loop will not run unless the array's length is also 0 (an empty array). The correct condition is i < array.length.
This "shift" you want can be achieved by creating a temporary variable inside the loop that is equal to the sum times 10i. In Java's Math library, there is a pow(a,b) function that computes ab. With that in mind, what you want is something like this:
int oldSum = 4 * 5;
for (int i = 0; i < array.length; i++) {
int newSum = oldSum * Math.pow(10,i);
}
Multiply by 10 instead, and use < (not >) like
int sum = 20;
int[] array = { 1, 2, 3 };
for (int i = 0; i < array.length; i++) {
int powSum = sum;
for (int j = array.length - 1; j > i; j--) {
powSum *= 10;
}
System.out.println(powSum);
}
Output is (as requested)
2000
200
20
For array of length = n; you will end up adding (n - 1) + (n - 2) + ... + 2 + 1 + 0 zeros for i = 0, 1, ... n-2, n-1 respectively.
Therefore, number of zeros to append (z) = n * (n-1) / 2
So the answer is sum * (10 ^ z)
[EDIT]
The above can be used to find the answer after N iteration. (I miss read the question)
int n = array.length;
long sum = 20;
long pow = Math.pow(10, n-1); // for i = 0
for (int i = 0; i < n; i++) {
System.out.println(sum*pow);
pow /= 10;
}

Minimum number of distinct characters to result in a given suffix array

Given a suffix array, a TopCoder task from SRM 630 asks to find the minium number of distinct characters in the string that could form a string with the given suffix array. The full problem statement can be found on the TopCoder website.
The best solution I found is right here: https://github.com/ftiasch/acm-icpc/blob/6db1ed02a727611830b974a1d4de38bab8f390f9/topcoder/single-round-match/single-round-match-630/SuffixArrayDiv1.java
Here is the algorithm written by ftiasch:
public int minimalCharacters(int[] array) {
int n = array.length;
int[] position = new int[n + 1];
for (int i = 0; i < n; ++i) {
position[array[i]] = i;
}
position[n] = -1;
int[] minimum = new int[n + 1];
for (int i = n - 1; i >= 0; --i) {
minimum[i] = Integer.MAX_VALUE;
for (int j = i + 1; j <= n; ++j) {
boolean valid = true;
for (int x = i; x < j; ++x) {
for (int y = x + 1; y < j; ++y) {
valid &= position[array[x] + 1] < position[array[y] + 1];
}
}
if (valid && minimum[j] < Integer.MAX_VALUE) {
minimum[i] = Math.min(minimum[i], minimum[j] + 1);
}
}
}
return minimum[0];
}
I understand that this is a dynamic programming algorithm but how does it work? I really need a hand understanding it.
EDIT
Here is what ftiasch wrote me back:
hi Ariel,
First of all, thanks to your compliment. Frankly speaking, my solution
is not the best solution to the problem. The optimal one runs in O(n)
time but mine takes O(n^4). I just picked this idea during the contest
because n is relatively small.
Keep in mind that same characters become continuous in the SA. Since
the problem asked for the least number of characters, so I decided to
use dynamic programming to partition the SA into consecutive segments
so that each segments start with the same character.
Which condition is necessary for S[SA[i]] == S[SA[j]] assumed that i <
j? The lexicographic comparison suggests that suffix(SA[i] + 1) should
be smaller than suffix(SA[j] + 1). We can easily find that the
condition is also sufficient.
Write to me if you have any other question. :)
EDIT1
We finally managed to make it work, thanks to David. Here is the linear time algorithm in java from David's Python version:
public int minimalCharacters(int[] array) {
int n = array.length, i;
if (n == 0)
return 0;
int[] array1 = new int[n + 1];
for (i = 0; i < n; i++)
array1[1 + i] = array[i];
int[] position = new int[n + 1];
for (i = 0; i < n + 1; i++)
position[array1[i]] = i;
int k = 1;
for (i = n; i > 1; i--) {
if (position[array1[i] + 1] <= position[array1[i - 1] + 1])
k++;
}
return k;
}
Here’s a quadratic-time algorithm. The suffix array specifies for each
pair of suffixes how they compare lexicographically (and the empty
suffix always is less than all of them). Let s be the unknown string
and suppose that we’re comparing suffix s[i...] with suffix s[j...].
If s[i] != s[j], then the comparison of s[i] and s[j] settles it.
Otherwise, the result is the same as if we compare s[i+1...] and
s[j+1...].
Suppose that we wish to ensure that s[i...] < s[j...]. Clearly we need
s[i] <= s[j]. In fact, unless s[i+1...] < s[j+1...], we need the
strict inequality s[i] < s[j], as otherwise the tiebreaker will go the
wrong way. Otherwise, s[i] == s[j] will suffice regardless of the rest
of the string. Gather up all of the inequalities as arcs in a directed
graph with vertices corresponding to positions in s. This graph is
necessarily acyclic by the total order on suffixes. Make each arc length
1 if the inequality is strict and length 0 otherwise. Output the length
of the longest path, plus one (or zero if the graph is empty).
At least this many distinct letters are needed, by the corresponding
chain of inequalities. What’s perhaps less clear is that this many
distinct letters suffices, but if we determine the label of each
vertex/position in s by the length of the longest path starting there,
then the head and tail of each arc are labeled appropriately.
To get down to linear time, we can exploit the structure of the
graph. It’s straightforward (though not trivial; the graph is metric
after all) to show that the path visiting all vertices of the graph is
the longest, so we merely have to compute its length.
Below are a transliterated version of the sample code (minChars1), an
implementation straight from the description above (minChars2, now
stripped of all comprehension usage), a brute force solution
(minChars3), and the linear-time solution (minChars4).
import itertools
def minChars1(array):
n = len(array)
position = [-1] * (n + 1)
for i in range(n):
position[array[i]] = i
infinity = n + 1
minimum = [infinity] * (n + 1)
minimum[n] = 0
for i in range(n - 1, -1, -1):
for j in range(i + 1, n + 1):
valid = True
for x in range(i, j):
for y in range(x + 1, j):
valid = valid and position[array[x] + 1] < position[array[y] + 1]
if valid and minimum[j] < infinity:
minimum[i] = min(minimum[i], minimum[j] + 1)
return minimum[0]
def lengthOfLongestPath(graph, memo, i):
if i not in memo:
result = 0
for w, j in graph[i]:
result = max(result, w + lengthOfLongestPath(graph, memo, j))
memo[i] = result
return memo[i]
def minChars2(array):
n = len(array)
position = [-1] * (n + 1)
for i in range(n):
position[array[i]] = i
graph = {}
for i in range(n):
graph[i] = []
for j in range(n):
if position[i] > position[j]:
w = 0 if position[i + 1] > position[j + 1] else 1
graph[i].append((w, j))
memo = {None: -1}
for i in range(n):
lengthOfLongestPath(graph, memo, i)
return max(memo.values()) + 1
def minChars3(array):
n = len(array)
position = [None] * n
for i in range(n):
position[array[i]] = i
for k in range(n):
for s in itertools.product(range(k), repeat=n):
valid = True
for i in range(n):
for j in range(n):
valid = valid and (s[i:] < s[j:]) == (position[i] < position[j])
if valid:
return k
return n
def minChars4(array):
n = len(array)
if n == 0:
return 0
array1 = [n] * (n + 1)
for i in range(n):
array1[1 + i] = array[i]
position = [None] * (n + 1)
for i in range(n + 1):
position[array1[i]] = i
k = 1
for i in range(n, 1, -1):
if position[array1[i] + 1] <= position[array1[i - 1] + 1]:
k += 1
return k
def test():
for n in range(7):
for array in itertools.permutations(range(n)):
assert minChars1(array) == minChars2(array) == minChars3(array) == minChars4(array)
test()

Categories