I am trying to solve:
https://www.spoj.com/problems/ANARC05B/
I am using Binary Search to solve this problem.
I think I have followed the correct approach.
Can anybody help me with a test case that would fail?
Below is my code, it passes on the sample test cases, i dont see a problem with my code but still not sure why i get WA!! Please help!!
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
using namespace std;
int BinarySearch(vector<int> arr, int key)
{
int minNum = 0;
int maxNum = arr.size() - 1;
while (minNum <= maxNum)
{
int mid = (minNum + maxNum) / 2;
if (key == arr[mid])
{
return mid;
}
else if (key < arr[mid])
{
maxNum = mid - 1;
}
else
{
minNum = mid + 1;
}
}
return -1;
}
signed long Solve(vector<int> First, vector<int> Second)
{
// Find the intersections in both the arrays and store the indices for them.
vector<int> FirstInterIndices;
vector<int> SecondInterIndices;
for (int i = 0; i < Second.size(); i++)
{
int idx = BinarySearch(First, Second[i]);
if (idx != -1)
{
SecondInterIndices.push_back(i);
FirstInterIndices.push_back(idx);
}
}
if (FirstInterIndices.empty())
{
FirstInterIndices.push_back(FirstInterIndices.size() - 1);
SecondInterIndices.push_back(SecondInterIndices.size() - 1);
}
//Find Intersections ends
//Calc the sum upto intersections in both the arrays and store them
vector<signed long> FirstInterSum;
vector<signed long> SecondInterSum;
for (int i = 0; i < SecondInterIndices.size(); i++)
{
int k = 0;
signed long Sum = 0;
if (i > 0)
{
k = SecondInterIndices[i - 1] + 1;
}
for (; k <= SecondInterIndices[i]; k++)
{
Sum += (signed long)Second[k];
}
SecondInterSum.push_back(Sum);
}
signed long SumLeft = 0;
if (SecondInterIndices.size() > 0)
{
for (int k = SecondInterIndices[SecondInterIndices.size() - 1] + 1; k < Second.size(); k++)
{
SumLeft += (signed long)Second[k];
}
SecondInterSum.push_back(SumLeft);
}
for (int i = 0; i < FirstInterIndices.size(); i++)
{
int k = 0;
signed long Sum = 0;
if (i > 0)
{
k = FirstInterIndices[i - 1] + 1;
}
for (; k <= FirstInterIndices[i]; k++)
{
Sum += (signed long)First[k];
}
FirstInterSum.push_back(Sum);
}
if (FirstInterIndices.size() > 0)
{
SumLeft = 0;
for (int k = FirstInterIndices[FirstInterIndices.size() - 1] + 1; k < First.size(); k++)
{
SumLeft += (signed long)First[k];
}
FirstInterSum.push_back(SumLeft);
}
// Calc sum upto intersections ENDs
// Compare corresponding elements (sum upto intersections) and add the max from First and Second
signed long MaxSum = 0;
int j = 0;
for (; j < FirstInterSum.size(); j++)
{
if (j < SecondInterSum.size())
{
if (FirstInterSum[j] > SecondInterSum[j])
{
MaxSum += FirstInterSum[j];
}
else
{
MaxSum += SecondInterSum[j];
}
}
}
// If Any sum exists after last intersection add that as well.
if (j < FirstInterSum.size())
{
MaxSum += FirstInterSum[FirstInterSum.size() - 1];
}
if (j < SecondInterSum.size())
{
MaxSum += SecondInterSum[SecondInterSum.size() - 1];
}
return MaxSum;
}
vector<int> getArray()
{
vector<int> res;
int n;
cin >> n;
int x;
for (int i = 0; i < n; i++)
{
cin >> x;
res.push_back(x);
}
return res;
}
int main()
{
for (;;)
{
vector<int> First = getArray();
if (First.size() == 0)
return 0;
vector<int> Second = getArray();
cout << Solve(First, Second);
}
return 0;
}
You get WA because the output format is incorrect. I ran your code, and the output looks like this:
13 3 5 7 9 20 25 30 40 55 56 57 60 62
11 1 4 7 11 14 25 44 47 55 57 100
4 -5 100 1000 1005
3 -12 1000 1001
0450
2100
Program ended with exit code: 0
but the expected format should be:
13 3 5 7 9 20 25 30 40 55 56 57 60 62
11 1 4 7 11 14 25 44 47 55 57 100
4 -5 100 1000 1005
3 -12 1000 1001
0
450
2100
Program ended with exit code: 0
difference is 0 and 450 are not on the same line.
But this problem does not require neither binary search nor dynamic programming (as it is marked at the site) and might be solved in linear time (the best possible)
Make two indices - for the first array and for the second one.
At every step move index that refers to smaller element (like in merge procedure of merge sort). When moving, calculate current sum (sum between intersection points).
When both indices point to equal values, you have found intersection point. Choose larger current sum from both arrays, add it and intersection item to result, reset sums to zero.
Pseudocode sketch
if a[ia] < b[ib])
asum += a[ia++]
else
if a[ia] > b[ib])
bsum += b[ib++]
else
result += max(asum, bsum) + a[ia]
asum = bsum = 0
ia++
ib++
Related
I participated in a programming competition at my University. I solved all the questions except this one. Now I am practicing this question to improve my skills. But I can't figure out the algorithm. If there is any algorithm existing please update me. Or any similar algorithm is present then please tell me I will change it according to this question.
This is what I want to do.
The First line of input is the distance between two points.
After that, each subsequent line contains a pair of numbers indicating the length of cable and quantity of that cable. These cables are used to join the two points.
Input is terminated by 0 0
Output:
The output should contain a single integer representing the minimum number of joints possible to build the requested length of cableway. If no solution possible than print "No solution".
Sample Input
444
16 2
3 2
2 2
30 3
50 10
45 12
8 12
0 0
Sample Output
10
Thanks guys. I found a solution from "Perfect subset Sum" problem and then made a few changes in it. Here's the code.
#include <bits/stdc++.h>
using namespace std;
bool dp[100][100];
int sizeOfJoints = -1;
void display(const vector<int>& v)
{
if (sizeOfJoints == -1)
{
sizeOfJoints = v.size() - 1;
}
else if (v.size()< sizeOfJoints)
{
sizeOfJoints = v.size() - 1;
}
}
// A recursive function to print all subsets with the
// help of dp[][]. Vector p[] stores current subset.
void printSubsetsRec(int arr[], int i, int sum, vector<int>& p)
{
// If sum becomes 0
if (sum == 0)
{
display(p);
return;
}
if(i<=0 || sum<0)
return;
// If given sum can be achieved after ignoring
// current element.
if (dp[i-1][sum])
{
// Create a new vector to store path
//vector<int> b = p;
printSubsetsRec(arr, i-1, sum, p);
}
// If given sum can be achieved after considering
// current element.
if (sum >= arr[i-1] && dp[i-1][sum-arr[i-1]])
{
p.push_back(arr[i-1]);
printSubsetsRec(arr, i-1, sum-arr[i-1], p);
p.pop_back();
}
}
// all subsets of arr[0..n-1] with sum 0.
void printAllSubsets(int arr[], int n, int sum)
{
if (n == 0 || sum < 0)
return;
// If sum is 0, then answer is true
for (int i = 0; i <= n; i++)
dp[i][0] = true;
// If sum is not 0 and set is empty, then answer is false
for (int i = 1; i <= sum; i++)
dp[0][i] = false;
// Fill the subset table in botton up manner
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= sum; j++)
{
if(j<arr[i-1])
dp[i][j] = dp[i-1][j];
if (j >= arr[i-1])
dp[i][j] = dp[i-1][j] ||
dp[i - 1][j-arr[i-1]];
}
}
if (dp[n][sum] == false)
{
return;
}
// Now recursively traverse dp[][] to find all
// paths from dp[n-1][sum]
vector<int> p;
printSubsetsRec(arr, n, sum, p);
}
// Driver code
int main()
{
int input[2000];
int inputIndex = 0;
int i = 0;
int distance = 0;
cout<< "Enter Input: " <<endl;
cin>> distance;
while(true)
{
int temp1 = 0;
int temp2 = 0;
cin>> temp1;
cin>> temp2;
if (temp1 == 0 && temp2 == 0)
{
break;
}
for (i = 0; i < temp2; i++)
input[inputIndex++] = temp1;
}
cout<< "Processing output. Please wait: " <<endl;
printAllSubsets(input, inputIndex, distance);
if(sizeOfJoints != -1)
cout<<sizeOfJoints;
else
cout<<"No Solution Possible";
return 0;
}
The question Maximal Square in https://leetcode.com/problems/maximal-square/description/ is easy to solve by DP. But how to solve the following up question:
Similar as Maximal Square question, but allows 0's inside a square, "inside" means the border of the square must be all 1.
For example, given the following matrix:
1 0 1 0 0
1 0 1 1 1
1 1 1 0 1
1 0 1 1 1
Return 9.
Update: Because the 3*3 matrix in the right bottom corner matches the requirement, the border must be all 1, and there can be 0 inside the square.
I thought up a O(n^3) algorithm: take maze[i][j] as the right bottom corner of the square if maze[i][j] == 1, enumerate the edge length of the square. If edge length is 3, consider whether maze[i - 2][j - 2], maze[i][j - 2], maze[i - 2][j], maze[i][j] forms a square with the numbers in each edge are all 1.
Is there any better algorithm?
Your problem can be solved in O (n * m) time and space complexity, where n is total rows and m is total columns in matrix. You may look at the code below where I have commented out to make it understandable.
Please, let me know if you have any doubt.
#include <bits/stdc++.h>
using namespace std;
void precalRowSum(vector< vector<int> >& grid, vector< vector<int> >&rowSum, int n, int m) {
// contiguous sum upto jth position in ith row
for (int i = 0; i < n; ++i) {
int sum = 0;
for (int j = 0; j < m; ++j) {
if (grid[i][j] == 1) {
sum++;
} else {
sum = 0;
}
rowSum[i][j] = sum;
}
}
}
void precalColSum(vector< vector<int> >& grid, vector< vector<int> >&colSum, int n, int m) {
// contiguous sum upto ith position in jth column
for (int j = 0; j < m; ++j) {
int sum = 0;
for (int i = 0; i < n; ++i) {
if (grid[i][j] == 1) {
sum++;
} else {
sum = 0;
}
colSum[i][j] = sum;
}
}
}
int solve(vector< vector<int> >& grid, int n, int m) {
vector< vector<int> >rowSum(n, vector<int>(m, 0));
vector< vector<int> >colSum(n, vector<int>(m, 0));
// calculate rowwise sum for 1
precalRowSum(grid, rowSum, n, m);
// calculate colwise sum for 1
precalColSum(grid, colSum, n, m);
vector< vector<int> >zerosHeight(n, vector<int>(m, 0));
int ans = 0;
for (int i = 0; i < (n - 1); ++i) {
for (int j = 0; j < m; ++j) {
zerosHeight[i][j] = ( grid[i][j] == 0 );
if (grid[i][j] == 0 && i > 0) {
zerosHeight[i][j] += zerosHeight[i - 1][j];
}
}
if (i == 0) continue;
// perform calculation on ith row
for (int j = 1; j < m; ) {
int height = zerosHeight[i][j];
if (!height) {
j++;
continue;
}
int cnt = 0;
while (j < m && height == zerosHeight[i][j]) {
j++;
cnt++;
}
if ( j == m) break;
if (cnt == height && (i - cnt) >= 0 ) {
// zeros are valid, now check validity for boundries
// Check validity of upper boundray, lower boundary, left boundary, right boundary respectively
if (rowSum[i - cnt][j] >= (cnt + 2) && rowSum[i + 1][j] >= (cnt + 2) &&
colSum[i + 1][j - cnt - 1] >= (cnt + 2) && colSum[i + 1][j] >= (cnt + 2) ){
ans = max(ans, (cnt + 2) * (cnt + 2) );
}
}
}
}
return ans;
}
int main() {
int n, m;
cin>>n>>m;
vector< vector<int> >grid;
for (int i = 0; i < n; ++i) {
vector<int>tmp;
for (int j = 0; j < m; ++j) {
int x;
cin>>x;
tmp.push_back(x);
}
grid.push_back(tmp);
}
cout<<endl;
cout<< solve(grid, n, m) <<endl;
return 0;
}
My implementation of max sum is below but i need sequence which is giving max sum i looked on google and stackoverflow but nowhere sequence is output.
public int maxSum(int arr[]) {
int excl = 0;
int incl = arr[0];
for (int i = 1; i < arr.length; i++) {
int temp = incl;
incl = Math.max(excl + arr[i], incl);
excl = temp;
}
return incl;
}
So 3 2 7 10 should return (3 and 10) or 3 2 5 10 7 should return (3, 5 and 7) or {5, 5, 10, 100, 10, 5} will return (5, 100 and 5) or {1, 20, 3} will return 20
i exactly want this problem solution but return value i need is sequence of elements included in max sum instead of max sum value
You mean that in this array: [1,3,4,2,4,7,5,3] , calculate [1+4+4+5] and [3+2+7+3]
and return the bigger one?
If you do so, this is my algorithm:
public int maxSum(int arr[]) {
int sum1 = 0;
int sum2 = 0;
for(int i = 0; i < arr.length; i+=2)
sum1 += arr[i];
for(int i = 1; i < arr.length; i+=2)
sum2 += arr[i];
return Math.max(sum1, sum2);
}
Or this one:
public int maxSum(int arr[]) {
int sum1 = 0;
int sum2 = 0;
for(int i = 0; i < arr.length; i+=2)
sum1 += arr[i];
try {sum2 += arr[i + 1];} catch(ArrayIndexOutOfBoundsException e){}
}
return Math.max(sum1, sum2);
}
Looks similar to Longest Increasing Fragment problem(Top Down approach.)
Instead of having length of sequence, you can return sum of it. Also, instead of skipping one, skipping two to avoid adjacent elements.
#simplest and clean solution
public int maxSubsetSumNoAdjacent(int[] arr) {
if(arr.length == 0){
return 0;
}
if(arr.length == 1){
return arr[0];
}
int a =arr[0];
int b= 0;
int c =a;
int i=1;
while(i<arr.length){
a=arr[i]+b;
b=Math.max(c,b);
c=a;
i++;
}
return Math.max(a,b);
}
I am trying to parallelize the addition of two simple 4x4 matrices. The child process adds only odd rows and the parents adds even ones. However, I can't seem to get the processes to work on shared pointer memory and the output is always given in halves, shown beneath the code:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main() {
int A[4][4] = {{1,2,3,4},{6,7,8,9},{11,12,13,14},{16,17,18,19}};
int B[4][4] = {{1,2,3,4},{6,7,8,9},{11,12,13,14},{16,17,18,19}};
int** C = (int**)malloc(sizeof(int)*4);
for (int z = 0; z<4; z++) {
C[z] = (int*)malloc(sizeof(int)*4);
}
pid_t cp;
printf("Before fork\n");
cp = fork();
if (cp == 0) {
for(int i = 1; i < 4; i+=2) {
for(int j = 0; j < 4; j++) {
printf("child process\n");
printf("We are adding cell %d,%d\n",i,j);
C[i][j] = A[i][j] + B[i][j];
sleep(1);
}
}
} else {
for (int k = 0; k < 4; k+=2) {
for(int l = 0; l < 4; l++) {
printf("parent process\n");
printf("We are adding cell %d,%d\n",k,l);
C[k][l] = A[k][l] + B[k][l];
sleep(1);
}
}
}
sleep(10);
printf("We are printing C here\n");
for (int m = 0; m < 4; m++) {
for(int n = 0; n < 4; n++) {
printf("%d ",C[m][n]);
}
printf("\n");
}
}
This is the output of the final for loop in the above code:
We are printing C here
0 0 0 0
12 14 16 18
0 0 0 0
32 34 36 38
We are printing C here
2 4 6 8
0 0 0 0
22 24 26 28
0 0 0 0
for n = 3:
1 3 6
2 5 8
4 7 9
this is diffrent from diagonal printing.
If we are given n then we have to print in 2d matrix from upto n.
public static int[][] zigzag(final int size)
{
int[][] data = new int[size][size];
int i = 1;
int j = 1;
for (int element = 0; element < size * size; element++)
{
data[i - 1][j - 1] = element;
if ((i + j) % 2 == 0)
{
// Even stripes
if (j < size)
j++;
else
i+= 2;
if (i > 1)
i--;
}
else
{
// Odd stripes
if (i < size)
i++;
else
j+= 2;
if (j > 1)
j--;
}
}
return data;
}