This is a question from a ZCO (Zonal Computing Olympiad; Indian IOI qualifying contest) paper.
Basically, it revolves around finding the number of distinct pairs of elements from a set of numbers whose sum does not exceed a certain value.
My solution works on all except the last test case (on a certain private server, the test case itself is not available), on which it exceeds the 3-second time limit by half a second.
Am I missing something, algorithmically? A few pointers would be nice.
Here is my code:
#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
int main() {
int n, k;
cin >> n >> k;
vector<int> hardness;
hardness.reserve(n);
int temp;
for(int i = 1; i <= n; ++i) {
cin >> temp;
if (temp < k) {
hardness.push_back(temp);
}
}
sort(hardness.begin(), hardness.end());
int mx = hardness.back(); //Max element
int chewableCombinations = 0, cur = 0;
for(int i = 0; i < hardness.size() - 1; ++i) {
cur = hardness[i];
if(cur == 0 || cur + mx < k) {
chewableCombinations += hardness.size() - i - 1;
continue;
}
for(int j = i + 1; j < hardness.size(); ++j) {
if(cur + hardness[j] < k) {
++chewableCombinations;
} else break; //we've crossed the limit
}
}
cout << chewableCombinations << endl;
}
If hardness[i]+hardness[j] < k then hardness[i]+hardness[m] < k for all m < j.
You don't have to check them all.
Related
So i was solving my homework, and i did this piece of code which is supposed to find the biggest difference beetween two prime numbers in the interval of [a,b], and i got "Process returned -1073741819 (0xC0000005)"
#include <iostream>
#include <vector>
#include <bitset>
using namespace std;
bitset <10000000>v;
int main()
{
for (int i = 2; i < 10000000; i++)
{
if (v[i] == 0)
{
for (int j = i * i; j < 10000000; j += i)
v[j] = 1;
}
}
int n, a, b, maxi = 0, mini = 0, smax = 0;
cin >> a >> b;
int poz = a;
while (v[poz] == 1)
poz++;
int prev = poz;
poz++;
while (v[poz] == 1 && poz < b)
poz++;
if (poz == b && v[b] == 1)
{
cout << -1; return 0;
}
int next = poz;
poz++;
while (poz <= b)
{
if (next - prev > smax)
{
smax = next - prev;
maxi = next;
mini = prev;
}
if (v[poz] == 0)
{
prev = next;
next = poz;
}
poz++;
}
cout << mini << " " << maxi;
return 0;
}
i expected 43 with 47
In your initialisation loop when i is 46349, i*i is 2,148,229,801, this is larger than fits inside a signed 32-bit integer so evaluates to -2,146,737,495. v[j] then causes the crash.
You should either modify your code to use a larger data type or set the limit for i to sqrt(10000000) rather than 10000000.
I'm guessing that i*i overflows when i is large, leading to a negative value for j and an access violation on v[j]=1;.
You have a potential segmentation fault on line v[j]=1; where j may exceed 10000000.
Please check your boundaries.
Homework: I'm just stumped as hell. I have algorithms set up, but I have no idea how to code this
Just to be clear you do not need arrays or to pass variables by reference.
The purpose of the project is to take a problem apart and using Top-Down_Design or scratch pad method develop the algorithm.
Problem:
Examine the numbers from 2 to 10000. Output the number if it is a Dual_Prime.
I will call a DualPrime a number that is the product of two primes. Ad where the two primes are not equal . So 9 is not a dual prime. 15 is ( 3 * 5 ) .
The output has 10 numbers on each line.
My Algorithm set-up
Step 1: find prime numbers.:
bool Prime_Number(int number)
{
for (int i = 2; i <= sqrt(number); i++)
{
if (number % 1 == 0)
return false;
}
return true;
}
Step 2: store prime numbers in a array
Step 3: Multiply each array to each other
void Multiply_Prime_Numbers(int Array[], int Size)
{
for (int j = 0; j < Size- 1; j++)
{
Dual_Prime[] = Arr[j] * Arr[j + 1]
}
}
Step 4: Bubble sort
void Bubble_Sort(int Array[], int Size) // Sends largest number to the right
{
for (int i = Size - 1; i > 0; i--)
for (int j = 0; j < i; j++)
if (Array[j] > Array[j + 1])
{
int Temp = Array[j + 1];
Array[j + 1] = Array[j];
Array[j] = Temp;
}
}
Step 5: Display New Array by rows of 10
void Print_Array(int Array[], int Size)
{
for (int i = 0; i < Size; i++)
{
cout << Dual_Prime[i] << (((j % 10) == 9) ? '\n' : '\t');
}
cout << endl;
}
I haven't learned dynamic arrays yet,
Although dynamic arrays and the sieve of Eratosthenes are more preferable, I tried to write minimally fixed version of your code.
First, we define following global variables which are used in your original implementation of Multiply_Prime_Numbers.
(Please check this post.)
constexpr int DP_Size_Max = 10000;
int DP_Size = 0;
int Dual_Prime[DP_Size_Max];
Next we fix Prime_Number as follows.
The condition number%1==0 in the original code is not appropriate:
bool Prime_Number(int number)
{
if(number<=1){
return false;
}
for (int i = 2; i*i <= number; i++)
{
if (number % i == 0)
return false;
}
return true;
}
In addition, Multiply_Prime_Numbers should be implemented by double for-loops as follows:
void Multiply_Prime_Numbers(int Array[], int Size)
{
for (int i = 0; i < Size; ++i)
{
for (int j = i+1; j < Size; ++j)
{
Dual_Prime[DP_Size] = Array[i]*Array[j];
if(Dual_Prime[DP_Size] >= DP_Size_Max){
return;
}
++DP_Size;
}
}
}
Then these functions work as follows.
Here's a DEMO of this minimally fixed version.
int main()
{
int prime_numbers[DP_Size_Max];
int size = 0;
for(int j=2; j<DP_Size_Max; ++j)
{
if(Prime_Number(j)){
prime_numbers[size]=j;
++size;
}
}
Multiply_Prime_Numbers(prime_numbers, size);
Bubble_Sort(Dual_Prime, DP_Size);
for(int i=0; i<DP_Size;++i){
std::cout << Dual_Prime[i] << (((i % 10) == 9) ? '\n' : '\t');;
}
std::cout << std::endl;
return 0;
}
The Sieve of Eratosthenes is a known algorithm which speeds up the search of all the primes up to a certain number.
The OP can use it to implement the first steps of their implementation, but they can also adapt it to avoid the sorting step.
Given the list of all primes (up to half the maximum number to examine):
Create an array of bool as big as the range of numbers to be examined.
Multiply each distinct couple of primes, using two nested loops.
If the product is less than 10000 (the maximum) set the corrisponding element of the array to true. Otherwise break out the inner loop.
Once finished, traverse the array and if the value is true, print the corresponding index.
Here there's a proof of concept (implemented without the OP's assignment restrictions).
// Ex10_TwoPrimes.cpp : This file contains the 'main' function. Program execution begins and ends there.
#include "pch.h"
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
void Homework_Header(string Title);
void Do_Exercise();
void Sieve_Of_Eratosthenes(int n);
void Generate_Semi_Prime();
bool Semi_Prime(int candidate);
bool prime[5000 + 1];
int main()
{
Do_Exercise();
cin.get();
return 0;
}
void Do_Exercise()
{
int n = 5000;
Sieve_Of_Eratosthenes(n);
cout << endl;
Generate_Semi_Prime();
}
void Sieve_Of_Eratosthenes(int n)
{
// Create a boolean array "prime[0..n]" and initialize
// all entries it as true. A value in prime[i] will
// finally be false if i is Not a prime, else true.
memset(prime, true, sizeof(prime));
for (int p = 2; p*p <= n; p++)
{
// If prime[p] is not changed, then it is a prime
if (prime[p] == true)
{
// Update all multiples of p
for (int i = p * p; i <= n; i += p)
prime[i] = false;
}
}
}
bool Semi_Prime(int candidate)
{
for (int index = 2; index <= candidate / 2; index++)
{
if (prime[index])
{
if (candidate % index == 0)
{
int q = candidate / index;
if (prime[q] && q != index)
return true;
}
}
}
return false;
}
void Generate_Semi_Prime()
{
for (int i = 2; i <= 10000; i++)
if (Semi_Prime(i)) cout << i << "\t";
}
I am trying to make a C++ program of the FourSum problem i.e. Does there exist a sum of four different numbers that sum to zero.
"i + j + k + l = 0" "-2 + -1 + 3 + 0 = 0"
I can get it to work, but the running time is around 10-15 times slower than the java implementation (both are naive approaches, so basically just four for loops). I know it is possible to use BinarySearch for the last loop, provided you sort the array. But it was my understanding that generally C++ should perform better and run faster than Java and certainly also Python. So how do I do that?
Any or all suggestions are welcome. Thanks.
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>
using namespace std;
int main () {
string line;
int N;
ifstream myfile ("ints/ints-400-1.txt");
getline(myfile,line);
stringstream into(line);
into >> N;
std::vector<long long> vals (N);
if (myfile.is_open())
{
int i = 0;
while ( getline(myfile,line) ) {
vals[i] = stoll( line );
++i;
}
myfile.close();
}
else cout << "Unable to open file";
for (int i = 0; i != vals.size(); i++) {
for (int j = i + 1; j != vals.size(); j++) {
for (int k = j + 1; k != vals.size(); k++) {
for (int l = k + 1; l != vals.size(); l++) {
if (vals[i] + vals[j] + vals[k] +vals[l] == 0) {
cout << "true";
}
}
}
}
}
return 0;
}
I am trying to teach myself C++ in preparation for graduate school this coming fall but I am having some trouble with this birthday paradox problem. My code seems to run ok but I am not getting the correct output. If anyone has any suggestions please let me know.
#include <cstdlib>
#include <iostream>
#include <ctime>
using namespace std;
int main()
{
srand(time(NULL));
const int trials = 100000;
int birthdays[50];
int numMatches;
for(int i = 2; i <= 50; i++)
{
numMatches = 0;
for(int j = 1; j <= trials; j++)
{
for(int k = 1; k <= i; k++)
{
birthdays[k] = (rand() % 365) + 1;
}
int m = 1;
bool matched = false;
while(m < i && !matched){
int n = m + 1;
while(n <= i && !matched){
if(birthdays[m] == birthdays[n]){
numMatches++;
matched = true;
}
n++;
}
m++;
}
}
cout << "Probability of " << i << " people in a room sharing a birthday is \t"
<< ( float(numMatches) / float(trials) ) << endl;
}
}
Your code is not computing the probability of two people in a room of 50 sharing a birthday. There's several bugs, mostly with indexing, but here's the biggest issue:
for(int j = 1; j <= trials; j++) {
// assigns a random birthday to the first i people (should be 0 indexed)
for(k = 1; k <= i; k++)
birthdays[k] = (rand() % 365) + 1;
// Does *exactly* the same thing as the previous loop, overwriting what
// the initial loop did. Useless code
for(m = 1; m <= i; m++)
birthdays[m] = (rand() % 365) + 1;
// At this point, m = k = i + 1. Here you check if
// the i + 1st array value has the same b-day. It will, because they're
// the same thing. Note you never set the i + 1st value so the loops
// above did nothing
if(birthdays[k] == birthdays[m])
++numMatches;
}
So what you've got here is something like:
Perform 48 iterations of the following (from your first loop which goes from 2 to 50: no idea where those values came from)
For each of those 48 iterations, perform 10k iterations of:
assign a bunch of random stuff to an array overwriting stuff
Ignore the values you wrote in the array, do a comparison that's always true and increment numMatches by 1
Consider what's going on here:
for(int j = 1; j <= trials; j++) {
for(k = 1; k <= i; k++)
birthdays[k] = (rand() % 365) + 1;
for(m = 1; m <= i; m++)
birthdays[m] = (rand() % 365) + 1;
if(birthdays[k] == birthdays[m])
++numMatches;
}
You go through i birthdays and assign a random number, then you go through the same i birthdays and assign them a new random number. Then you try to find a match for just one value of k and m (which both happen to equal i+1, which isn't one of the values set!).
My suggestion is to break the problem down into smaller units that will make it easier to figure out how to code - here are the functions I would try to write.
/* randomizeBirthdays()
* Put n random birthdays into the pre-allocated array birthdays.
* birthdays must of course be of length <= n.
*/
void randomizeBirthdays(int * birthdays, int n);
/* hasMatchingBirthdays()
* Check if birthdays array has two people with the same birthday
* in the first n entries.
* Return value is boolean.
*/
bool hasMatchingBirthdays(int * const birthdays, int n);
/* probabilityOfMatch()
* Calculate the probability that at least 2 out of n people will
* have the same birthday, using nTrials number of trials.
* Return value is double.
*/
double probabilityOfMatch(int n, int nTrials);
If you break it down like this it becomes easier to write and easier to troubleshoot.
As I said in comments already:
I think your aim is to test if 2 people in room of 2-50 people share
birthday, not if 2-50 people share birthday as you say in output. And
that's 2 people out of 23 have 50.7%, not 24.
I completely reworked your code:
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
#define DAYS_IN_YEAR 365
#define TRIALS 10000
void clearArray (bool * array)
{
for (int i = 0; i < DAYS_IN_YEAR; i++)
array[i] = false;
}
int main()
{
srand(time(NULL));
bool birthdays[DAYS_IN_YEAR]; //we are trying to hit same day in year twice
int r, numMatches;
for(int i = 2; i < 50; i++)
{
numMatches = 0;
for(int j = 0; j < TRIALS; j++)
{
clearArray(birthdays);
for(int k = 0; k < i; k++)
{
r = rand() % DAYS_IN_YEAR; // == 0-364
if (birthdays[r])
{
numMatches++;
break; // 2 people already have same birthdays here
}
birthdays[r] = true;
}
}
cout << "Probability of 2 people having same birthday in room of " << i << " people is "
<< (float)numMatches / TRIALS << endl;
}
}
Output:
Probability of 2 people having same birthday in room of 23 people is 0.516
I think the code must be something like this.
#include <cstdlib>
#include <iostream>
#include <ctime>
using namespace std;
int main() {
srand(time(NULL));
int birthdays[10000][50];
int numMatches;
int trials=10000,check;
for(int n=0;n<trials;n++)
{
for(int j=0;j<50;j++)
{
birthdays[n][j]=rand()%365+1;
}
}
for(int i=2;i<=50;i++)
{
numMatches=0;
for(int n=0;n<trials;n++)
{
check=1;
for(int j=0;j<i;j++)
{
for(int k=j+1;k<=i;k++)
{
if(birthdays[n][j]==birthdays[n][k]&&check)
{
numMatches++;
check=0;
}
}
}
}
cout << "Probability of " << i << " people in a room sharing a birthday is \t" <<
(static_cast<float>(numMatches) / (trials)) << endl;
}
}
I am trying to partition an array using a quicksort algorithm shown in the code. I believe the problem is in the while loop. Can you see/explain what I'm doing wrong and what I should do to fix it? Thanks!
Edited because I posted an earlier version of the code.
#include <iostream>
#include <ctime>
#include <cstdlib>
using namespace std;
int intArray[10];
int sizeArray= 10;
int main(){
srand(time(0));
for(int i = 0; i < sizeArray; i++){
//random numbers from 1 to 10:
intArray[i] = rand() % 100 + 1;
}
for(int i = 0; i < sizeArray; i++){
cout << intArray[i] << " ";
}
int *pivot = &intArray[0];
int *first = &intArray[1];
int *last = &intArray[9];
cout<<"pivot "<<*pivot <<endl;
while(first<last)
{
while(*first<*pivot)
{
first++;
}
while(*last>*pivot)
{
last--;
}
if(*first>*last)
{
int aSwap = 0;
aSwap = *first;
*first = *last;
*last = aSwap;
}
if((first-1) > last)
break;
}
int bSwap=0;
bSwap = *first;
*first= *pivot;
*pivot = bSwap;
cout<<"After partition"<<endl;
for(int i = 0; i < sizeArray; i++){
cout << intArray[i] << " ";
}
}
I'll give you one immediate peice of advice re:
while(*first<*pivot)
If your pivot at array[0] is the largest value in the array, you're going to run off the end of the array and keep going, resulting in undefined behaviour.
The termination condition for that loop should include detecting if the first pointer has reached the last one.
Ditto for the loop that decrements last.
And, of course, once the pointers meet, there's no need to do a swap.
And your edit comparing the first against last values is actually worse. You're supposed to be looking for two values that you will swap across from where the pivot wiill eventually go.
I suggest reverting the code and simply adding the limiting check I suggested. Here is the correct code for doing the partition swapping operation, from some code I wrote not that long ago:
// Simplest form of pivot selection.
pvt = 0;
lft = 1;
rgt = 9;
// Continue until new pivot point found.
while (lft < rgt) {
// find value on left greater than pivot value.
while ((lft < rgt) && (array[lft] <= array[0]))
lft++;
// Then, assuming found, find value on right less than pivot value.
if (lft < rgt) {
while ((lft < rgt) && (array[rgt] >= array[0]))
rgt--;
// Swap them if found.
if (lft < rgt)
SWAP (array[lft], array[rgt]);
}
}
// Back up to find proper swap point for pivot value, then swap.
while ((lft > 0) && (array[lft] >= array[0]))
lft--;
if (lft != 0)
SWAP (array[lft], array[0]);
// Now everything left of pivot is less than pivot value, everything
// right is greater/equal. Go and sort the two sections.
You are making your life too complicated.
GCC 4.7.3: g++ -Wall -Wextra main.cpp
#include <iostream>
#include <ctime>
#include <cstdlib>
using namespace std;
int intArray[10];
int sizeArray= 10;
int main() {
srand(time(0));
for (int i = 0; i < sizeArray; ++i) {
//random numbers from 1 to 10:
intArray[i] = rand() % 100 + 1; }
for(int i = 0; i < sizeArray; ++i){
cout << intArray[i] << " "; }
int* pivot = &intArray[0];
cout << "pivot " << *pivot << endl;
for (int i = 0; i < sizeArray; ++i) {
if (intArray[i] < *pivot) {
std::swap(intArray[i], *(pivot + 1)); // move the pivot ahead one
std::swap(*pivot, *(pivot + 1)); // move the value into the hole
++pivot; }}
cout<<"After partition"<<endl;
for (int i = 0; i < sizeArray; i++){
cout << intArray[i] << " "; }
return 0; }