patterncppMinor
UVA 10474 - “Where is the marble?”
Viewed 0 times
themarblewhere10474uva
Problem
I have been solving the problem from UVA 10474. In this problem, there will be marbles with numbers written on them. For example suppose five marbles with numbers 50 , 43, 43, 43, 2, 90, 44. There will be several query with number and position has to be told in a sorted sequence. For example after sorting these looks like : 2,43,43,43,44,50,90. Now, query for 43 will give output : 43 fond at 2 and query for -3 will output "-3 not found".
Can you please review it and provide me with feedback?
Can you please review it and provide me with feedback?
#include
#include
#include
#include
void printMarbelPositionIfFound()
{
int numMarbles, numQueries, aMarble, case1;
std::vectormarbles;
case1 = 0;
while(true)
{
scanf("%d %d", &numMarbles, &numQueries);
if(0 == numMarbles && 0 == numQueries)return;
case1++;
for(int i=0; i::const_iterator itr = std::lower_bound(marbles.begin(), marbles.end(),aMarble);
if(*itr == aMarble)
{
std::cout<<aMarble<<" found at "<<itr - marbles.begin() + 1<<'\n';
}
else
{
std::cout<<aMarble<<" not found"<<'\n';
}
}
marbles.clear();
}
}
int main()
{
printMarbelPositionIfFound();
return 0;
}Solution
You are mixing C with C++. I know these contests like speed, but it is usually unnecessary.
This means you can change this code:
Into this:
You have a C++11 tag, so I assume you have C++11 available.
You can change this:
To this:
In this line:
So change this line:
To this:
You have:
In the case an
Would be a better habit to get into.
You could create an object that represents a single unit of input. Something like this:
Then you could implement the member and friend functions like this:
Then your driver would look like this:
With the above code, I got an accepted answer with a runtime of 0.212 units on your website. So streams are more than fast enough for this particular challenge.
- Prefer streams over
scanf.
This means you can change this code:
scanf("%d %d", &numMarbles, &numQueries);Into this:
std::cin >> numMarbles >> numQueries ;- Use the C++11
autokeyword when possible.
You have a C++11 tag, so I assume you have C++11 available.
You can change this:
std::vector::const_iterator itr = std::lower_bound(marbles.begin(), marbles.end(),aMarble);To this:
auto itr = std::lower_bound(marbles.begin(), marbles.end(),aMarble);- Make sure the iterator does not point past the end when you dereference it.
In this line:
if(*itr == aMarble), you dereference the iterator. If aMarble is not in marbles, then std::lower_bound() will return marbles.end(). It is undefined behavior to dereference marbles.end(). Always check for this condition.So change this line:
if(*itr == aMarble)To this:
if (iter != marbles.end () && *itr == aMarble)- Prefer pre-increment over post-increment.
You have:
case1++;In the case an
int, it doesn't really matter. Your compiler will optimize this correctly. But if you had a complicated object, then you would be creating an unnecessary copy here. So:++case1;Would be a better habit to get into.
- Encapsulate input and output with an Object.
You could create an object that represents a single unit of input. Something like this:
struct Input
{
int nMarbles ;
int nQueries ;
static int caseNumber ;
std::vector marbles ;
std::vector queries ;
Input () ;
void Clear () ;
friend auto operator>> (std::istream &is, Input &input) -> std::istream& ;
friend auto operator std::ostream& ;
};Then you could implement the member and friend functions like this:
int Input::caseNumber = 0 ;
Input::Input () : nMarbles (), nQueries ()
{
}
void Input::Clear ()
{
nMarbles = 0 ;
nQueries = 0 ;
marbles.clear () ;
queries.clear () ;
}
auto operator>> (std::istream& is, Input &input) -> std::istream&
{
++Input::caseNumber ;
is >> input.nMarbles >> input.nQueries ;
if (input.nMarbles == 0 && input.nQueries == 0) {
is.setstate (std::ios::failbit) ;
return is ;
}
auto begin = std::istream_iterator (is) ;
std::copy_n (begin, input.nMarbles, std::back_inserter (input.marbles)) ;
begin = std::istream_iterator (is) ;
std::copy_n (begin, input.nQueries, std::back_inserter (input.queries)) ;
return is ;
}
auto operator std::ostream&
{
os << "CASE# " << Input::caseNumber << ":" "\n" ;
auto &marbles = input.marbles ;
std::sort (std::begin (marbles), std::end (marbles)) ;
for (int query : input.queries) {
auto iter = std::lower_bound (std::begin (marbles), std::end (marbles), query) ;
if (iter != std::end (marbles) && *iter == query) {
os << query << " found at " << (std::distance (std::begin (marbles), iter) + 1) << "\n" ;
}
else {
os << query << " not found" "\n" ;
}
}
return os ;
}Then your driver would look like this:
int main ()
{
Input input ;
while (std::cin >> input) {
std::cout << input ;
input.Clear () ;
}
return 0 ;
}With the above code, I got an accepted answer with a runtime of 0.212 units on your website. So streams are more than fast enough for this particular challenge.
Code Snippets
scanf("%d %d", &numMarbles, &numQueries);std::cin >> numMarbles >> numQueries ;std::vector<int>::const_iterator itr = std::lower_bound(marbles.begin(), marbles.end(),aMarble);auto itr = std::lower_bound(marbles.begin(), marbles.end(),aMarble);if(*itr == aMarble)Context
StackExchange Code Review Q#73397, answer score: 4
Revisions (0)
No revisions yet.