The problem I am working on is as follows. Imagine a 4x4 chess board on top of which you place a king. The probability of you placing the king on each of the squares is one of the inputs (not necessarily the same for all the squares). The king has to make n number of moves (n is an input). The goal is to run an 'experiment' to find the probability after n moves.
My friend solved the problem by creating a general formula using linear algebra. As a challenge/verification of his answer I want to make this program in c++.
We both start with making one generalization. That is since the board is symmetrical we only consider if the king is at a side, corner or middle square of the board.
C S S C
S M M S
S M M S
C S S C
Therefore, we input only P(S_{initial}), P(C_{initial}), P(M_{initial}), the number of moves the king makes, and the number of 'experiments' we make.
The code for my program is below. My results disagreed with my friend's, so I checked my code by setting n to 1 and P(S_{initial}), P(C_{initial}) and P(M_{initial}) to 1/2, 1/4, and 1/4, respectively. By conditional probability I know that P(S)=59/120, P(C)=21/160, P(M)=181/481. My computations do not agree, so I am sure there is a bug or error in my code, but I cannot track it down. I appreciate any help.
Also I know my code is scruffy and inefficient so I appreciate comments about how to improve it. Thanks for your help.
EDIT: To input the initial probabilities I input 2, 1 and 1 for S, C and M, respectively.
EDIT2: Turned out that I used "=" instead of the operator "==" in my if statements. Thank you #Christopher Oicles. Everything works now as expected.
#include <iostream>
#include <string>
#include <cstdlib>
#include <cmath>
#include <stdio.h>
#include <time.h>
using namespace std;
int S, C, M; //probability 'ratios', i.e. prob of S is S/(S+C+M)
int n; // number of steps
int trials;
int initial(int a,int b,int c); // this 'throws the die' to find where to start and returns 0 for side, 1 for corner, 2 for middle
int step(int a); // this throws the die to make a step and returns the same format
int trial(); //this makes n number of steps, starting at initial(a,b,c) and returns 0,1,2
double data[]={0,0,0}; // the result of the experiment, each element holds the number of times a trial returned the S,C,M where number of s = data[0], I increment this by one every time I run trial();
int main()
{
srand(time(NULL));
for(int i=0;i<3;i++) //reset data array
data[i]=0;
std::cout << "Enter probability ratio of S:";
std::cin >> S;
std::cout << "Enter probability ratio of C:";
std::cin >> C;
std::cout << "Enter probability ratio of M:";
std::cin >> M;
std::cout << "Enter number of steps per trial:";
std::cin >> n;
std::cout << "Enter number of trials:";
std::cin >> trials;
for(int i=0;i<trials;i++)
data[trial()]++;
for(int i=0;i<3;i++)
std::cout << data[i]/trials << " \n";
for(int i=0;i<3;i++)
std::cout<<data[i]<<" ";
cout << "\n \n";
}
int trial(){
int current;// the current place S, C or M or 0,1,2
int next;
current = initial(S,C,M);
for(int i=0;i<n;i++)
{next = step(current);
current = next;}
return current;
}
int initial(int side,int corner,int middle){
int t = rand() % (side+corner+middle); //generates a random number from zero to a+b+c-1
//now we apply the probability
if(t < side)
return 0; //side
if(t >= side && t < (side+corner))
return 1; //corner
if(t>=(side+corner))
return 2; //middle
}
int step(int a){
int t;
switch(a){
case 0: //we are on a side
{t = rand()%5;
if(t < 2){return 0;} //2/5 chance to go to a side
if(t = 2){return 1;} //1/5 chance to go to a corner
if(t > 2){return 2;} //2/5 chance to go to a middle
break;}
case 1: //we are on corner
{t = rand()%3;
if(t < 2){return 0;} //2/3 chance to go to side
if(t = 2){return 2;} //1/3 chance to go to middle
break;}
case 2: //we are on middle
{t = rand()%8;
if(t < 4){return 0;} //1/2 chance go to side
if(t = 4){return 1;} //1/8 chance of corner
if(t > 4){return 2;} //3/8 chance of middle
break;}
}
}
Related
I have to write a program that outputs Pascal's triangle for a computer science class, and everything is correct on the output until it gets past row 14, wherein it starts outputting odd irrational numbers. Here's my code
#include <iostream>
#include "myFunctions.h"
using namespace std;
int main() {
int rows;
cout << "Please Enter The Number of Rows: ";
cin >> rows;
cout << rows << endl;
for (int i = 0; i < rows; i++) {
for (int j = 1; j < (rows - i + 1); j++) {
cout << " ";
}
for (int k = 0; k <= i; k++) {
if (k == 0) {
cout << "1" << " ";
} else {
cout << combination(i, k) << " ";
}
}
cout << "\n";
}
return 0;
}
And here's my functions file:
#ifndef MYFUNCTIONS_CPP_INCLUDED
#define MYFUNCTIONS_CPP_INCLUDED
#include "myFunctions.h"
double factorial (int n) {
assert(n >= 0);
int v = 1;
while (n > 0) {
v *= n;
n--;
}
return v;
}
double combination (int a, int b) {
return (factorial(a) / (factorial(a - b) * factorial(b)));
}
#endif // MYFUNCTIONS_CPP_INCLUDED
And, finally, here's my header file.
#ifndef MYFUNCTIONS_H_INCLUDED
#define MYFUNCTIONS_H_INCLUDED
#include <iostream>
#include <cassert>
//*******************************************************
// description: finds factorial of value *
// return: double *
// precondition: that the value is valid and an integer *
// postcondition: returns the factorial of value *
//*******************************************************
double factorial( int n );
//********************************************************
// description: finds combination of value *
// return: double *
// precondition: both values are integers and valid *
// postcondition: returns the combination of two values *
//********************************************************
double combination( int a, int b );
#endif // MYFUNCTIONS_H_INCLUDED
I'm assuming that I did the equations within functions incorrect, or something specific is happening in main once it hits 14. Any help is appreciated.
What's going on
ints in C++ have a maximum size. As mentioned in comments, depends on your platform but for the sake of this question, I'll assume it's 2^31-1 which corresponds to a 32-bit signed integer and is what I most commonly see.
The issue comes in when you get to factorials. They grow very quickly. 14!=87178291200 which is a whole lot bigger than the maximum size of a 32 bit int. There's no feasible way to keep the whole factorial in memory for an arbitrary n! because of how large they can get.
It's not that your code is broken, it's simply running up against the physical bounds of computing.
How can we fix it?
First off, you could cancel out factorials. Basically, since we can guarantee that a>=b, we know that a!/b! is just multiplying the numbers between a and b. We can do that with a loop. Then it's just a matter of dividing by (a-b)!, which we already know how to do. This would look like
int combination(int a, int b)
{
int tmp = 1;
for(int ii = b;ii<=a;ii++)
tmp*=ii;
tmp /= factorial(b);
return tmp;
}
More efficiently, we can switch to a different algorithm. Wikipedia recommends using an iterative method for pascal's triangle. That is, each element can be calculated from two elements in the row above it. As #Damien mentions in comments, if you're looking for the kth element in row n, then you can calculate that by
int Combination(int n,int k)
{
if (k == 0 or k>n or n <= 1)
return 1;
return Combination(n-1,k) + Combination(n-1,k-1);
}
I have a program like this: given a sequence of integers, find the biggest prime and its positon.
Example:
input:
9 // how many numbers
19 7 81 33 17 4 19 21 13
output:
19 // the biggest prime
1 7 // and its positon
So first I get the input, store it in an array, make a copy of that array and sort it (because I use a varible to keep track of the higest prime, and insane thing will happen if that was unsorted) work with every number of that array to check if it is prime, loop through it again to have the positon and print the result.
But the time is too slow, can I improve it?
My code:
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
int main()
{
int n;
cin >> n;
int numbersNotSorted[n];
int maxNum{0};
for (int i = 0; i < n; i++)
{
cin >> numbersNotSorted[i];
}
int numbersSorted[n];
for (int i = 0; i < n; i++)
{
numbersSorted[i] = numbersNotSorted[i];
}
sort(numbersSorted, numbersSorted + n);
for (int number = 0; number < n; number++)
{
int countNum{0};
for (int i = 2; i <= sqrt(numbersSorted[number]); i++)
{
if (numbersSorted[number] % i == 0)
countNum++;
}
if (countNum == 0)
{
maxNum = numbersSorted[number];
}
}
cout << maxNum << '\n';
for (int i = 0; i < n; i++)
{
if (numbersNotSorted[i] == maxNum)
cout << i + 1 << ' ';
}
}
If you need the biggest prime, sorting the array brings you no benefit, you'll need to check all the values stored in the array anyway.
Even if you implemented a fast sorting algorithm, the best averages you can hope for are O(N + k), so just sorting the array is actually more costly than looking for the largest prime in an unsorted array.
The process is pretty straight forward, check if the next value is larger than the current largest prime, and if so check if it's also prime, store the positions and/or value if it is, if not, check the next value, repeat until the end of the array.
θ(N) time compexity will be the best optimization possible given the conditions.
Start with a basic "for each number entered" loop:
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
int main() {
int n;
int newNumber;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> newNumber;
}
}
If the new number is smaller than the current largest prime, then it can be ignored.
int main() {
int n;
int newNumber;
int highestPrime;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> newNumber;
if(newNumber >= highestPrime) {
}
}
}
If the new number is equal to the highest prime, then you just need to store its position somewhere. I'm lazy, so:
int main() {
int n;
int newNumber;
int highestPrime;
int maxPositions = 1234;
int positionList[maxPositions];
int nextPosition;
int currentPosition = 0;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> newNumber;
currentPosition++;
if(newNumber >= highestPrime) {
if(newNumber == highestPrime) {
if(nextPosition+1 >= maxPositions) {
// List of positions is too small (should've used malloc/realloc instead of being lazy)!
} else {
positionList[nextPosition++] = currentPosition;
}
}
}
}
}
If the new number is larger than the current largest prime, then you need to figure out if it is a prime number, and if it is you need to reset the list and store its position, etc:
int main() {
int n;
int newNumber;
int highestPrime = 0;
int maxPositions = 1234;
int positionList[maxPositions];
int nextPosition;
int currentPosition = 0;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> newNumber;
currentPosition++;
if(newNumber >= highestPrime) {
if(newNumber == highestPrime) {
if(nextPosition+1 >= maxPositions) {
// List of positions is too small (should've used malloc/realloc instead of being lazy)!
} else {
positionList[nextPosition++] = currentPosition;
}
} else { // newNumber > highestPrime
if(isPrime(newNumber)) {
nextPosition = 0; // Reset the list
highestPrime = newNumber;
positionList[nextPosition++] = currentPosition;
}
}
}
}
}
You'll also want something to display the results:
if(highestPrime > 0) {
for(nextPosition= 0; nextPosition < currentPosition; nextPosition++) {
cout << positionList[nextPosition];
}
}
Now; the only thing you're missing is an isPrime(int n) function. The fastest way to do that is to pre-calculate a "is/isn't prime" bitfield. It might look something like:
bool isPrime(int n) {
if(n & 1 != 0) {
n >>= 1;
if( primeNumberBitfield[n / 32] & (1 << (n % 32)) != 0) {
return true;
}
}
return false;
}
The problem here is that (for positive values in a 32-bit signed integer) you'll need 1 billion bits (or 128 MiB).
To avoid that you can use a much smaller bitfield for numbers up to sqrt(1 << 31) (which is only about 4 KiB); then if the number is too large for the bitfield you can use the bitfield to find prime numbers and check (with modulo) if they divide the original number evenly.
Note that Sieve of Eratosthenes ( https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes ) is an efficient way to generate that smaller bitfield (but is not efficient to use for a sparse population of larger numbers).
If you do it right, you'll probably create the illusion that it's instantaneous because almost all of the work will be done while a human is slowly typing the numbers in (and not left until after all of the numbers have been entered). For a very fast typist you'll have ~2 milliseconds between numbers, and (after the last number is entered) humans can't notice delays smaller than about 10 milliseconds.
But the time is too slow, can I improve it?
Below loop suffers from:
Why check smallest values first? Makes more sense to check largest values first to find the largest prime. Exit the for (... number..) loop early once a prime is found. This takes advantage of the work done by sort().
Once a candidate value is not a prime, quit testing for prime-ness.
.
// (1) Start for other end rather than as below
for (int number = 0; number < n; number++) {
int countNum {0};
for (int i = 2; i <= sqrt(numbersSorted[number]); i++) {
if (numbersSorted[number] % i == 0)
// (2) No point in continuing prime testing, Value is composite.
countNum++;
}
if (countNum == 0) {
maxNum = numbersSorted[number];
}
}
Corrections left for OP to implement.
Advanced: Prime testing is a deep subject and many optimizations (trivial and complex) exist that are better than OP's approach. Yet I suspect the above 2 improvement will suffice for OP.
Brittleness: Code does not well handle the case of no primes in the list or n <= 0.
i <= sqrt(numbersSorted[number]) is prone to FP issues leading to an incorrect results. Recommend i <= numbersSorted[number]/i).
Sorting is O(n * log n). Prime testing, as done here, is O(n * sqrt(n[i])). Sorting does not increase O() of the overall code when the square root of the max value is less than log of n. Sorting is worth doing if the result of the sort is used well.
Code fails if the largest value was 1 as prime test incorrectly identifies 1 as a prime.
Code fails if numbersSorted[number] < 0 due to sqrt().
Simply full-range int prime test:
bool isprime(int num) {
if (num % 2 == 0) return num == 2;
for (int divisor = 3; divisor <= num / divisor; divisor += 2) {
if (num % divisor == 0) return false;
}
return num > 1;
}
If you want to find the prime, don't go for sorting. You'll have to check for all the numbers present in the array then.
You can try this approach to do the same thing, but all within a lesser amount of time:
Step-1: Create a global function for detecting a prime number. Here's how you can approach this-
bool prime(int n)
{
int i, p=1;
for(i=2;i<=sqrt(n);i++) //note that I've iterated till the square root of n, to cut down on the computational time
{
if(n%i==0)
{
p=0;
break;
}
}
if(p==0)
return false;
else
return true;
}
Step-2: Now your main function starts. You take input from the user:
int main()
{
int n, i, MAX;
cout<<"Enter the number of elements: ";
cin>>n;
int arr[n];
cout<<"Enter the array elements: ";
for(i=0;i<n;i++)
cin>>arr[i];
Step-3: Note that I've declared a counter variable MAX. I initialize this variable as the first element of the array: MAX=arr[0];
Step-4: Now the loop for iterating the array. What I did was, I iterated through the array and at each element, I checked if the value is greater than or equal to the previous MAX. This will ensure, that the program does not check the values which are less than MAX, thus eliminating a part of the array and cutting down the time. I then nested another if statement, to check if the value is a prime or not. If both of these are satisfied, I set the value of MAX to the current value of the array:
for(i=0;i<n;i++)
{
if(arr[i]>=MAX) //this will check if the number is greater than the previous MAX number or not
{
if(prime(arr[i])) //if the previous condition satisfies, then only this block of code will run and check if it's a prime or not
MAX=arr[i];
}
}
What happens is this- The value of MAX changes to the max prime number of the array after every single loop.
Step-5: Then, after finally traversing the array, when the program finally comes out of the loop, MAX will have the largest prime number of the array stored in it. Print this value of MAX. Now for getting the positions where MAX happens, just iterate over the whole loop and check for the values that match MAX and print their positions:
for(i=0;i<n;i++)
{
if(arr[i]==MAX)
cout<<i+1<<" ";
}
I ran this code in Dev C++ 5.11 and the compilation time was 0.72s.
So I was solving this USACO 2013 February Silver Contest - Perimeter - Problem 1.
Link to the problem: Problem Link
Link to the bronze version of this problem: Problem Link
Link to solutions: Silver - Link to Solution Bronze - Link to Solution
The problem:
Problem 1: Perimeter [Brian Dean, 2013]
Farmer John has arranged N hay bales (1 <= N <= 50,000) in the middle of
one of his fields. If we think of the field as a 1,000,000 x 1,000,000
grid of 1 x 1 square cells, each hay bale occupies exactly one of these
cells (no two hay bales occupy the same cell, of course).
FJ notices that his hay bales all form one large connected region, meaning
that starting from any bale, one can reach any other bale by taking a
series of steps either north, south, east, or west onto directly adjacent
bales. The connected region of hay bales may however contain "holes" --
empty regions that are completely surrounded by hay bales.
Please help FJ determine the perimeter of the region formed by his hay
bales. Note that holes do not contribute to the perimeter.
PROBLEM NAME: perimeter
INPUT FORMAT:
Line 1: The number of hay bales, N.
Lines 2..1+N: Each line contains the (x,y) location of a single hay
bale, where x and y are integers both in the range
1..1,000,000. Position (1,1) is the lower-left cell in FJ's
field, and position (1000000,1000000) is the upper-right cell.
SAMPLE INPUT (file perimeter.in):
8
10005 200003
10005 200004
10008 200004
10005 200005
10006 200003
10007 200003
10007 200004
10006 200005
INPUT DETAILS:
The connected region consisting of hay bales looks like this:
XX
X XX
XXX
OUTPUT FORMAT:
Line 1: The perimeter of the connected region of hay bales.
SAMPLE OUTPUT (file perimeter.out):
14
OUTPUT DETAILS:
The length of the perimeter of the connected region is 14 (for example, the
left side of the region contributes a length of 3 to this total). Observe
that the hole in the middle does not contribute to this number.
What I did
I went ahead with a recursive solution to the problem which goes like this :
#include <iostream>
#include <cmath>
#include <vector>
#include <algorithm>
#include <map>
using namespace std;
#define rep(i,a,b) for(auto (i)=a;i<b;i++)
#define list(i,N) for(auto (i)=0;i<N;i++)
typedef long long ll;
typedef vector<ll> vi;
typedef pair<ll,ll> pi;
#define mp make_pair
#define pb push_back
#define int ll
#define INF 1e18+5
#define mod 1000000007
//One map for storing whether a cell has hay bale or not
//And the other for visited - whether a cell has been visited or not
map<pi,bool> vis;
map<pi,bool> exists;
int ans = 0;
void solve(int i, int j){
//Check about the visited stuff
if(vis[mp(i,j)]) return;
vis[mp(i,j)] = true;
//Find the answer now
ans += 4;
if(exists[mp(i-1,j)]){
--ans; solve(i-1,j);
}
if(exists[mp(i+1,j)]){
--ans; solve(i+1,j);
}
if(exists[mp(i,j+1)]){
--ans; solve(i,j+1);
}
if(exists[mp(i,j-1)]){
--ans; solve(i,j-1);
}
}
int32_t main(){
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int N; cin >> N;
int first, second; //the starting point where we start the function...
while(N--){
int a,b; cin >> a >> b;
first = a; second = b; //in the end, it is just the coordinate specified in the last in the input...
exists[mp(a,b)] = true; //Hay Bale exists...
}
solve(first,second);
cout << ans << "\n";
return 0;
}
Basically, what I am doing is :
Start at a cell.
First, check if the cell has been previously visited. If yes, return. If not, make it visited.
Add 4 to the counter for all the four sides.
Look around the cell to all its neighbouring cells. If the cell also has haybales, subtract 1 from the counter (no need for adding boundary) and then goto 2.
The problem which I am facing
Observe that this code also counts the boundary required inside the hole. BUT we don't need to include that into our answer. I, however, don't know how to exclude that from our answer...
Why I mentioned the Bronze Problem
If you see the solution of the Bronze Problem (which is just the same problem but with different constraints), Mr Brian Dean also implements this sort of a recursive solution here which is similar to what I'm doing in my code. The code is down below :
#include <stdio.h>
#define MAX_N 100
int already_visited[MAX_N+2][MAX_N+2];
int occupied[MAX_N+2][MAX_N+2];
int perimeter;
int valid(int x, int y)
{
return x>=0 && x<=MAX_N+1 && y>=0 && y<=MAX_N+1;
}
void visit(int x, int y)
{
if (occupied[x][y]) { perimeter++; return; }
if (already_visited[x][y]) return;
already_visited[x][y] = 1;
if (valid(x-1,y)) visit(x-1,y);
if (valid(x+1,y)) visit(x+1,y);
if (valid(x,y-1)) visit(x,y-1);
if (valid(x,y+1)) visit(x,y+1);
}
int main(void)
{
int N, i, x, y;
freopen ("perimeter.in", "r", stdin);
freopen ("perimeter.out", "w", stdout);
scanf ("%d", &N);
for (i=0; i<N; i++) {
scanf ("%d %d", &x, &y);
occupied[x][y] = 1;
}
visit(0,0);
printf ("%d\n", perimeter);
return 0;
}
Why this solution does not work for the Silver
This is because the constraints in the Silver version of the problem which I'm solving has higher constraints but the same time limit. This times out the code.
So, I would be grateful if anybody could help me solve this problem in order to exclude the perimeter taken up by the hole in the middle.
Your solution is quite similar to the second one posted. But instead of walking on the bales, you walk on the perimeter:
void solve(int i, int j){
if(vis[mp(i,j)]) return;
if(exists[mp(i,j)]) return;
if(there_is_no_bale_next_to(i,j)) return; // consider all 8 directions
vis[mp(i,j)] = true;
ans ++;
solve(i-1,j);
solve(i+1,j);
solve(i,j+1);
solve(i,j-1);
}
You first run solve on a point definitely on perimeter(like the westmost point).
The problem with your solution is that it targets at the 'X' points, which will inevitably count the holes as well. Please consider to launch a floodfill that moves around the object without actually getting into it. My solution below implements this idea, so holes are not being counted. Brian Dean's solution in the official editorial is also based on this idea, so you should check out that as well.
#include<bits/stdc++.h>
using namespace std;
int n, ans = 0;
map<pair<int,int>, bool> m, vis;
pair<int,int> p = {INT_MAX, INT_MAX};
bool adj (int i, int j) {
for (int x = -1; x <= 1; x++) {
for (int y = -1; y <= 1; y++) {
if (!x & !y) continue;
if (m[{i + x, j + y}]) return true;
}
}
return false;
}
int get_cnt (int i, int j) {
int res = 0;
if (m[{i, j + 1}]) res++;
if (m[{i, j - 1}]) res++;
if (m[{i + 1, j}]) res++;
if (m[{i - 1, j}]) res++;
return res;
}
void floodfill (int i, int j) {
if (m[{i, j}] || vis[{i, j}] || !adj(i, j)) return;
vis[{i, j}] = true;
ans += get_cnt(i, j);
floodfill (i, j + 1);
floodfill (i, j - 1);
floodfill (i + 1, j);
floodfill (i - 1, j);
}
int main () {
cin >> n;
for (int i = 0; i < n; i++) {
int x, y;
cin >> x >> y;
m[{x, y}] = true;
p = min(p, {x, y});
}
floodfill (p.first - 1, p.second);
cout << ans << endl;
}
According to my lecturer a balanced number is balanced if the sum of its divisors is equal to it self. for example: 6 is a balanced number because 1+2+3=6
These are my very first homework so i am struggeling.
#include <iostream>
using namespace std;
int main() {
int num = 0;
int sum = 0;
cout << "Enter a number" << endl;
cin >> num;
if (num % (num-1) == 0 ){
for(int i =1; sum == 0; i++) {
sum += (num - i);
}
if (sum == num) {
cout << "Great Success" << endl;
}
else {
cout << "Wrong number" << endl;
}
}
}
Do the maths first. Often code being a bit messy is just a consequence of not preparing yourself good enough to write the code. Dont start writing code before you know what you want to write. Frankly, from your code one can see that it is something related to num-1 dividing num, but otherwise it is not clear how it is supposed to solve the problem. And its intendation makes it quite hard to read, so lets forget about the code and start from scratch...
y is a divisor of x exactly if x % y == 0. The biggest possible divisor of x is x/2. To get all divisors we can simply check every number from 2 up to x/2 (1 is always considered a divisor, hence no need to check).
Only now we can write some code:
int x;
std::cin >> x;
int sum = 1;
for (int y = 2; y <= x/2; ++y){
if ( check_if_y_is_divisor) { sum += y; }
}
bool is_balanced = sum == x;
I left a tiny hole in the code that you have to fill (I just dont like to give away the full solution when it is homework).
I was recently working on the following problem.
http://www.codechef.com/problems/D2
The Chef is planning a buffet for the DirectiPlex inauguration party, and everyone is invited. On their way in, each guest picks up a sheet of paper containing a random number (this number may be repeated). The guests then sit down on a round table with their friends.
The Chef now decides that he would like to play a game. He asks you to pick a random person from your table and have them read their number out loud. Then, moving clockwise around the table, each person will read out their number. The goal is to find that set of numbers which forms an increasing subsequence. All people owning these numbers will be eligible for a lucky draw! One of the software developers is very excited about this prospect, and wants to maximize the number of people who are eligible for the lucky draw. So, he decides to write a program that decides who should read their number first so as to maximize the number of people that are eligible for the lucky draw. Can you beat him to it?
Input
The first line contains t, the number of test cases (about 15). Then t test cases follow. Each test case consists of two lines:
The first line contains a number N, the number of guests invited to the party.
The second line contains N numbers a1, a2, ..., an separated by spaces, which are the numbers written on the sheets of paper in clockwise order.
Output
For each test case, print a line containing a single number which is the maximum number of guests that can be eligible for participating the the lucky draw.
Constraints
1 ≤ N ≤ 10000
You may assume that each number number on the sheet of paper; ai is randomly generated, i.e. can be with equal probability any number from an interval [0,U], where U is some upper bound (1 ≤ U ≤ 106).
Example
Input:
3
2
0 0
3
3 2 1
6
4 8 6 1 5 2
Output:
1
2
4
On checking the solutions I found this code:
#include <iostream>
#include <vector>
#include <stdlib.h>
#include <algorithm>
#define LIMIT 37
using namespace std;
struct node {
int val;
int index;
};
int N;
int binary(int number, vector<int>& ans) {
int start = 0;
int n = ans.size();
int end = n - 1;
int mid;
if (start == end)
return 0;
while (start != end) {
mid = (start + end) / 2;
if (ans[mid] == number)
break;
if (ans[mid] > number)
end = mid;
else
start = mid + 1;
}
mid = (start + end) / 2;
return mid;
}
void display(vector<int>& list) {
cout << endl;
for (int i = 0; i < list.size(); i++)
cout << list[i] << " ";
cout << endl;
}
int maxsubsequence(vector<int>& list) {
vector<int> ans;
int N = list.size();
ans.push_back(list[0]);
int i;
// display(list);
for (i = 1; i < N; i++) {
int index = binary(list[i], ans);
/*if(index+1<ans.size())
continue;*/
if (list[i] < ans[index])
ans[index] = list[i];
if (list[i] > ans[index])
ans.push_back(list[i]);
// display(ans);
}
return ans.size();
}
int compute(int index, int* g) {
vector<int> list;
list.push_back(g[index]);
int itr = (index + 1) % N;
while (itr != index) {
list.push_back(g[itr]);
itr = (itr + 1) % N;
}
return maxsubsequence(list);
}
int solve(int* g, vector<node> list) {
int i;
int ret = 1;
for (i = 0; i < min(LIMIT, (int)list.size()); i++) {
// cout<<list[i].index<<endl;
ret = max(ret, compute(list[i].index, g));
}
return ret;
}
bool cmp(const node& o1, const node& o2)
{ return (o1.val < o2.val); }
int g[10001];
int main() {
int t;
cin >> t;
while (t--) {
cin >> N;
vector<node> list;
int i;
for (i = 0; i < N; i++) {
node temp;
cin >> g[i];
temp.val = g[i];
temp.index = i;
list.push_back(temp);
}
sort(list.begin(), list.end(), cmp);
cout << solve(g, list) << endl;
}
return 0;
}
Can someone explain this to me. I am well aware of calculating LIS in nlog(n).
What I am not able to understand is this part:
int ret = 1;
for (i = 0; i < min(LIMIT, (int)list.size()); i++) {
// cout<<list[i].index<<endl;
ret = max(ret, compute(list[i].index, g));
}
and the reason behind sorting
sort(list.begin(),list.end(),cmp);
This algorithm is simply guessing at the starting point and computing the LIS for each of these guesses.
The first value in a LIS is likely to be a small number, so this algorithm simply tries the LIMIT smallest values as potential starting points.
The sort function is used to identify the smallest values.
The for loop is used to check each starting point in turn.
WARNING
Note that this algorithm may fail for certain inputs. For example, consider the sequence
0,1,2,..,49,9900,9901,...,99999,50,51,52,...,9899
The algorithm will try just the first 37 starting points and miss the best starting point at 50.
You can test this by changing the code to:
int main() {
int t;
t=1;
while (t--) {
N=10000;
vector<node> list;
int i;
for (i = 0; i < N; i++) {
node temp;
if (i<50)
g[i]=i;
else if (i<150)
g[i]=9999-150+i;
else
g[i]=i-100;
temp.val = g[i];
temp.index = i;
list.push_back(temp);
}
sort(list.begin(), list.end(), cmp);
cout << solve(g, list) << endl;
}
return 0;
}
This will generate different answers depending on whether LIMIT is 37 or 370.
In practice, for randomly generated sequences it will have a good chance of working (although I don't know how to compute the probability exactly).