CSES food division problem solving approach - algorithm

Has anyone tried to solve this particular problem? https://cses.fi/problemset/task/1189
Can someone help with an approach?

This works but doesn't optimize the steps
Tried recursion, but since the array 'a' needs to be updated, not sure how recursion can work in this case.
private int findMinSteps(int[] a, int[] b, int n) {
int cnt = 0;
do {
for(int i=1; i <= n; i++) {
if(a[i] == b[i]) continue;
if(a[i] > b[i]) { //we can give
if(a[left(i)] < b[left(i)]) { //give to left
a[i] -= 1;
a[left(i)] += 1;
cnt ++;
} else /*if(a[right(i)] < b[right(i)])*/ { //give to right
a[i] -= 1;
a[right(i)] += 1;
cnt ++;
}
} else { //we have to receive
if(a[left(i)] > b[left(i)]) { //receive from left`
a[i] += 1;
a[left(i)] -= 1;
cnt ++;
} else { //receive from right
a[i] += 1;
a[right(i)] -= 1;
cnt ++;
}
} //if-else
} //for
} while(!Arrays.equals(a, b));
return cnt;
} //findMinSteps

Here's a recursive solution that doesn't work either
private int findMinSteps(int[] a, int[] b, int n) {
/*if only one kid or zero kids are there, there is no mis-match
*because the total amount of food is correct
*/
//System.out.println(Arrays.toString(a));
//System.out.println(Arrays.toString(b));
if(n < 1)
return 0;
if(a[n] == b[n])
return findMinSteps(a, b, n-1);
if(a[n] > b[n]) {
//At each step a child can give 1 unit of food to neighbor
int l = left(n);
int r = right(n);
a[n] -= 1;
if(a[l] < b[l]) {
a[l] += 1;
} else if(a[r] < b[r]) {
a[r] += 1;
}
return 1+findMinSteps(a, b, n-1);
} else
return findMinSteps(a, b, n-1);
}

Related

UVA 861: From Backtracking to DP solution

Problem: Count the number of ways to place K Bishops on N*N chess board.
https://onlinejudge.org/external/8/861.pdf
I came up with the below backtracking solution but it is not fast enough. I do not understand the DP solution recommended on other sites. Can you please help.
In the below code I am exhaustively searching for all solutions using a recursive backtracking approach.
#include <bits/stdc++.h>
using namespace std;
using Row = vector<bool>;
using Board = vector<Row>;
Board gBoard;
bool isOk(int n, int r, int c) {
for(int i = r-1, j = c-1; i >= 0 && j >= 0; --i, --j) {
if(gBoard[i][j]) {
return false;
}
}
for(int i = r+1, j = c+1; i < n && j < n; ++i, ++j) {
if(gBoard[i][j]) {
return false;
}
}
for(int i = r-1, j = c+1; i >= 0 && j < n; --i, ++j) {
if(gBoard[i][j]) {
return false;
}
}
for(int i = r+1, j = c-1; i < n && j >= 0; ++i, --j) {
if(gBoard[i][j]) {
return false;
}
}
return true;
}
void trace(const string &msg) {
cout << msg << "\n";
for(int i = 0; i < gBoard.size(); ++i) {
for(int j = 0; j < gBoard[i].size(); ++j) {
cout << gBoard[i][j] << " ";
}
cout << "\n";
}
cout << "\n";
}
void dfs(int n, int k, int r, int c, int cnt, int &sum) {
if(cnt == k) {
//trace("OK");
++sum;
return;
}
if(c >= n) {
c = 0;
r += 1;
}
int j = c;
for(int i = r; i < n; ++i) {
for( ; j < n; ++j) {
if(gBoard[i][j]) {
continue;
}
gBoard[i][j] = true;
if(isOk(n, i,j)) {
//trace("tmp");
dfs(n, k, i, j+1, cnt+1, sum);
}
gBoard[i][j] = false;
}
j = 0;
}
}
void solve(int n, int k) {
gBoard.assign(n, Row(n, false));
int sum = 0;
dfs(n, k, 0, 0, 0, sum);
cout << sum << "\n";
}
int main() {
while(true) {
int n,k;
cin >> n >> k;
if(!n && !k) {
break;
}
solve(n, k);
}
return 0;
}
Thank you

Finding longest sequence of '1's in a binary array by replacing any one '0' with '1'

I have an array which is constituted of only 0s and 1s. Task is to find index of a 0, replacing which with a 1 results in the longest possible sequence of ones for the given array.
Solution has to work within O(n) time and O(1) space.
Eg:
Array - 011101101001
Answer - 4 ( that produces 011111101001)
My Approach gives me a result better than O(n2) but times out on long string inputs.
int findIndex(int[] a){
int maxlength = 0; int maxIndex= -1;
int n=a.length;
int i=0;
while(true){
if( a[i] == 0 ){
int leftLenght=0;
int j=i-1;
//finding count of 1s to left of this zero
while(j>=0){
if(a[j]!=1){
break;
}
leftLenght++;
j--;
}
int rightLenght=0;
j=i+1;
// finding count of 1s to right of this zero
while(j<n){
if(a[j]!=1){
break;
}
rightLenght++;
j++;
}
if(maxlength < leftLenght+rightLenght + 1){
maxlength = leftLenght+rightLenght + 1;
maxIndex = i;
}
}
if(i == n-1){
break;
}
i++;
}
return maxIndex;
}
The approach is simple, you just need to maintain two numbers while iterating through the array, the current count of the continuous block of one, and the last continuous block of one, which separated by zero.
Note: this solution assumes that there will be at least one zero in the array, otherwise, it will return -1
int cal(int[]data){
int last = 0;
int cur = 0;
int max = 0;
int start = -1;
int index = -1;
for(int i = 0; i < data.length; i++){
if(data[i] == 0){
if(max < 1 + last + cur){
max = 1 + last + cur;
if(start != -1){
index = start;
}else{
index = i;
}
}
last = cur;
start = i;
cur = 0;
}else{
cur++;
}
}
if(cur != 0 && start != -1){
if(max < 1 + last + cur){
return start;
}
}
return index;
}
O(n) time, O(1) space
Live demo: https://ideone.com/1hjS25
I believe the problem can we solved by just maintaining a variable which stores the last trails of 1's that we saw before reaching a '0'.
int last_trail = 0;
int cur_trail = 0;
int last_seen = -1;
int ans = 0, maxVal = 0;
for(int i = 0; i < a.size(); i++) {
if(a[i] == '0') {
if(cur_trail + last_trail + 1 > maxVal) {
maxVal = cur_trail + last_trail + 1;
ans = last_seen;
}
last_trail = cur_trail;
cur_trail = 0;
last_seen = i;
} else {
cur_trail++;
}
}
if(cur_trail + last_trail + 1 > maxVal && last_seen > -1) {
maxVal = cur_trail + last_trail + 1;
ans = last_seen;
}
This can be solved by a technique that is known as two pointers. Most two-pointers use O(1) space and O(n) time.
Code : https://www.ideone.com/N8bznU
#include <iostream>
#include <string>
using namespace std;
int findOptimal(string &s) {
s += '0'; // add a sentinel 0
int best_zero = -1;
int prev_zero = -1;
int zeros_in_interval = 0;
int start = 0;
int best_answer = -1;
for(int i = 0; i < (int)s.length(); ++i) {
if(s[i] == '1') continue;
else if(s[i] == '0' and zeros_in_interval == 0) {
zeros_in_interval++;
prev_zero = i;
}
else if(s[i] == '0' and zeros_in_interval == 1) {
int curr_answer = i - start; // [start, i) only contains one 0
cout << "tried this : [" << s.substr(start, i - start) << "]\n";
if(curr_answer > best_answer) {
best_answer = curr_answer;
best_zero = prev_zero;
}
start = prev_zero + 1;
prev_zero = i;
}
}
cout << "Answer = " << best_zero << endl;
return best_zero;
}
int main() {
string input = "011101101001";
findOptimal(input);
return 0;
}
This is an implementation in C++. The output looks like this:
tried this : [0111]
tried this : [111011]
tried this : [1101]
tried this : [10]
tried this : [01]
Answer = 4

Find Minimum Number in a Sorted and Rotated Array with Duplicate elements

I have worked on this problem for days but still, couldn't figure out a way to solve it. My solution can't solve some edge cases.
Problem:
Given an array and sorted in ascending order, rotate the array by k elements, find the index of the minimum number of the array(first element of the original non-rotated array).For example:
1. Give {3,4,1,3,3}, return 2.
2. Give {3,3,3,3,3}, return 0.
3. Give {1,1,4,1,1,1}, return 3.
Without duplicates, this problem can be solved in O(logn) time using binary search, with duplicates a modified binary search can be used, worst case time complexity is O(n).
My code:
public int FindPivot(int[] array)
{
var i = 0;
var j = array.Length - 1;
while (i < j)
{
var mid = i + (j - i) / 2 + 1;
if (array[mid] < array[array.Length - 1])
{
j = mid - 1;
}
else if (array[mid] > array[array.Length - 1])
{
i = mid;
}
else
{
if (array[mid] == array[j])
{
j--;
}
if (array[mid] == array[i])
{
i++;
}
}
}
return i+1;
}
It doesn't work if the input is {3,3,1,3,3,3,3,3}, it returns 3 while the correct answer is 2. Because at the last step is i points to index 2 and j moves from index 3 to index 2, it gets the correct element but i+1 makes the result wrong.What am I missing here?
I have modified your code as below and it seems works for all cases.
I cannot think of any good way to handle all the corner cases, because your original code kind of mix up the concept of the algorithm without duplicate elements (divide into two sub arrays) and two-pointers algorithm when there is duplicate elements.
I would say the problem is that the else case which is moving the two pointers did not cover all cases, like there are chances that you will go into else block with array[i] < array[mid]
Therefore I just modified it using newbie's method: Add two variables to keep track the minimum element and minimum index we found. Update it whenever the pointers move to cover all the cases possible. Return the index at the end. You cannot do something like return i+1 as it won't handle case for k = 0 which is no rotation at all ( {1,2,3,4})
The modified code is written in C# which I guess from your sample code.
PS: Though in average, this is faster than O(N) if the data is partially sorted without duplicate elements, it's worst case is still O(N) as you mentioned. So if I were you, I would just do a simple iteration and find the first minimum element...
Also from this reference, O(N) is the optimal you can reach if there are duplicate elements.
http://ideone.com/v3KVwu
using System;
public class Test
{
public static int FindPivot(int[] array)
{
var i = 0;
var j = array.Length - 1;
var ans = 1<<20;
var idx = 1<<20;
while (i < j)
{
var mid = i + (j - i) / 2 + 1;
// Console.WriteLine(String.Format("{0}, {1}, {2}", i, mid, j));
if (array[mid] < array[array.Length - 1])
{
if(array[mid] < ans || (array[mid] == ans && mid < idx)) { ans = array[mid]; idx = mid;}
j = mid - 1;
}
else if (array[mid] > array[array.Length - 1])
{
i = mid;
}
else
{
// Here did not consider case if array[i] < mid
if(array[j] < ans || (array[j] == ans && j < idx)) { ans = array[j]; idx = j;}
if(array[i] < ans || (array[i] == ans && i < idx)) { ans = array[i]; idx = i;}
if (array[mid] == array[j])
{
j--;
}
if (array[mid] == array[i])
{
i++;
}
}
}
if(array[j] < ans || (array[j] == ans && j < idx)) { ans = array[j]; idx = j;}
if(array[i] < ans || (array[i] == ans && i < idx)) { ans = array[i]; idx = i;}
Console.WriteLine("Minimum = " + ans);
return idx;
}
public static void Main()
{
int []a = {7,7,7,7,8,8,9,9,1,2,2,2,7,7};
int []b = {3,3,1,3,3,3,3,3};
int []c = {1,2,3,4};
int []d = {4,4,4,4};
int []e = {3,3,3,3,3,3,3,1,3};
int []f = {4,5,6,7,1,1,1,1};
Console.WriteLine(FindPivot(a));
Console.WriteLine(FindPivot(b));
Console.WriteLine(FindPivot(c));
Console.WriteLine(FindPivot(d));
Console.WriteLine(FindPivot(e));
Console.WriteLine(FindPivot(f));
}
}
Based on #shole's answer, I modified the code a little bit to cover cases like {1,1,1,1,3,1,1,1,1,1,1,1,1}.
public int FindPivot(int[] nums)
{
var i = 0;
var j = nums.Length - 1;
var ans = int.MaxValue;
var idx = int.MaxValue;
while (i < j)
{
var mid = i + (j - i) / 2 + 1;
if (nums[mid] < nums[nums.Length - 1])
{
if (nums[mid] < ans || (nums[mid] == ans && mid < idx)) { ans = nums[mid]; idx = mid; }
j = mid - 1;
}
else if (nums[mid] > nums[nums.Length - 1])
{
i = mid;
}
else
{
if (nums[j] < ans || (nums[j] == ans && j < idx)) { ans = nums[j]; idx = j; }
if (nums[mid] == nums[j])
{
j--;
}
if (nums[mid] == nums[i])
{
i++;
}
}
}
// Deal with cases like {1,1,1,1,1}
if (nums[i] == nums[nums.Length - 1] && nums[i] == nums[0] && i == j)
{
return 0;
}
if (nums[j] < ans || (nums[j] == ans && j < idx)) { ans = nums[j]; idx = j; }
return idx;
}

Implementation of Quick Sort

#include<stdio.h>
#include<iostream.h>
#include<conio.h>
void quicks(int *arr,int x,int pivot,int lo,int hi);
void swap1(int *x,int *y);
int main()
{
int *arr = new int[7];
arr[0] = 23;
arr[1] = 3;
arr[2] = -23;
arr[3] = 45;
arr[4] = 12;
arr[5] = 76;
arr[6] = -65;
quicks(arr,7,0,1,6);
for(int i = 0;i<7;i++)
std::cout << arr[i] <<"\t";
getch();
return 0;
}
void quicks(int *arr,int x,int pivot,int lo,int hi)
{
int i = lo,j = hi;
if(pivot < x-1)
{
while(i <= hi)
{
if(arr[i] <= arr[pivot])
i++;
else
break;
}
while(j >= lo)
{
if(arr[j] >= arr[pivot])
j--;
else
break;
}
if( i > j)
{
swap1(&arr[j],&arr[pivot]);
lo = pivot+1;
hi = x - 1;
quicks(arr,x,pivot,lo,hi);
}
else if(i == j)
{
pivot = pivot + 1;
lo = pivot+1;
hi = x - 1;
quicks(arr,x,pivot,lo,hi);
}
else if(i < j)
{
swap1(&arr[j],&arr[i]);
lo = i + 1;
hi = j - 1;
quicks(arr,x,pivot,lo,hi);
}
}
else
{
printf("\nDONE\n");
}
}
void swap1(int *x,int *y)
{
int temp;
temp = *x;
*x = *y;
*y = temp;
}
Hi,
I have written a program to implement Quick sort.But the program is going into an infinite loop.In the Quicks function,the while loops for incrementing and decrementing i and j are the problem.Can anybody tell me what is wrong with this Implementation of QUick Sort.
Do a quick dry run using your input and the algorithm, you'll notice you run into an infinite cycle after a while.
You are starting the loop from quicks(arr,7,0,1,6);. Try instead by setting low to the "rightmost" element, that is 0. This won't definitely solve your problem as the algorithm seems really flawed, with the position of high not changing at all, and i moving all the way to high. You're trying to complicate a very simple task.
i would go from lo to pivot. And j from hi to pivot. After the pivot is found to be in the right place, you'll move forward pivot and lo by 1, and repeat the process.
Take a look at this image, you'll get an idea of the algo required:

Euclidean greatest common divisor for more than two numbers

Can someone give an example for finding greatest common divisor algorithm for more than two numbers?
I believe programming language doesn't matter.
Start with the first pair and get their GCD, then take the GCD of that result and the next number. The obvious optimization is you can stop if the running GCD ever reaches 1. I'm watching this one to see if there are any other optimizations. :)
Oh, and this can be easily parallelized since the operations are commutative/associative.
The GCD of 3 numbers can be computed as gcd(a, b, c) = gcd(gcd(a, b), c). You can apply the Euclidean algorithm, the extended Euclidian or the binary GCD algorithm iteratively and get your answer. I'm not aware of any other (smarter?) ways to find a GCD, unfortunately.
A little late to the party I know, but a simple JavaScript implementation, utilising Sam Harwell's description of the algorithm:
function euclideanAlgorithm(a, b) {
if(b === 0) {
return a;
}
const remainder = a % b;
return euclideanAlgorithm(b, remainder)
}
function gcdMultipleNumbers(...args) { //ES6 used here, change as appropriate
const gcd = args.reduce((memo, next) => {
return euclideanAlgorithm(memo, next)}
);
return gcd;
}
gcdMultipleNumbers(48,16,24,96) //8
I just updated a Wiki page on this.
[https://en.wikipedia.org/wiki/Binary_GCD_algorithm#C.2B.2B_template_class]
This takes an arbitrary number of terms.
use GCD(5, 2, 30, 25, 90, 12);
template<typename AType> AType GCD(int nargs, ...)
{
va_list arglist;
va_start(arglist, nargs);
AType *terms = new AType[nargs];
// put values into an array
for (int i = 0; i < nargs; i++)
{
terms[i] = va_arg(arglist, AType);
if (terms[i] < 0)
{
va_end(arglist);
return (AType)0;
}
}
va_end(arglist);
int shift = 0;
int numEven = 0;
int numOdd = 0;
int smallindex = -1;
do
{
numEven = 0;
numOdd = 0;
smallindex = -1;
// count number of even and odd
for (int i = 0; i < nargs; i++)
{
if (terms[i] == 0)
continue;
if (terms[i] & 1)
numOdd++;
else
numEven++;
if ((smallindex < 0) || terms[i] < terms[smallindex])
{
smallindex = i;
}
}
// check for exit
if (numEven + numOdd == 1)
continue;
// If everything in S is even, divide everything in S by 2, and then multiply the final answer by 2 at the end.
if (numOdd == 0)
{
shift++;
for (int i = 0; i < nargs; i++)
{
if (terms[i] == 0)
continue;
terms[i] >>= 1;
}
}
// If some numbers in S are even and some are odd, divide all the even numbers by 2.
if (numEven > 0 && numOdd > 0)
{
for (int i = 0; i < nargs; i++)
{
if (terms[i] == 0)
continue;
if ((terms[i] & 1) == 0)
terms[i] >>= 1;
}
}
//If every number in S is odd, then choose an arbitrary element of S and call it k.
//Replace every other element, say n, with | n−k | / 2.
if (numEven == 0)
{
for (int i = 0; i < nargs; i++)
{
if (i == smallindex || terms[i] == 0)
continue;
terms[i] = abs(terms[i] - terms[smallindex]) >> 1;
}
}
} while (numEven + numOdd > 1);
// only one remaining element multiply the final answer by 2s at the end.
for (int i = 0; i < nargs; i++)
{
if (terms[i] == 0)
continue;
return terms[i] << shift;
}
return 0;
};
For golang, using remainder
func GetGCD(a, b int) int {
for b != 0 {
a, b = b, a%b
}
return a
}
func GetGCDFromList(numbers []int) int {
var gdc = numbers[0]
for i := 1; i < len(numbers); i++ {
number := numbers[i]
gdc = GetGCD(gdc, number)
}
return gdc
}
In Java (not optimal):
public static int GCD(int[] a){
int j = 0;
boolean b=true;
for (int i = 1; i < a.length; i++) {
if(a[i]!=a[i-1]){
b=false;
break;
}
}
if(b)return a[0];
j=LeastNonZero(a);
System.out.println(j);
for (int i = 0; i < a.length; i++) {
if(a[i]!=j)a[i]=a[i]-j;
}
System.out.println(Arrays.toString(a));
return GCD(a);
}
public static int LeastNonZero(int[] a){
int b = 0;
for (int i : a) {
if(i!=0){
if(b==0||i<b)b=i;
}
}
return b;
}

Resources