Website Customer Visit Count

May 3rd, 2011 | by | technology

May
03

Question: A leading shopping website generates logs everyday of customers visiting their website along with the page number that they visited. Each entry contains the customer unique id and the page id, which the customer visited. Given the logs of 3 days, and the customer id, check whether the customer visited exactly on 2 out of 3 days and also check whether he visited more than 3 different pages?

#include <iostream>
#include <hash_map>
#include <list>
#include <set>
#include <bitset>
#include <string>

using namespace std;
using namespace stdext;

const int PAGE_VIEW_COUNT = 3;
const int DAYS_VISIT_COUNT = 2;

class CustomerData
{
public:
  bitset<PAGE_VIEW_COUNT> days;
  set<int> pages;

  CustomerData(bitset<PAGE_VIEW_COUNT> d, set<int> p) : days(d), pages(p)
  {
  }

  CustomerData() : days(string("000")) //Use days.reset, if PAGE_VIEW_COUNT != 3
  {
  }
};

hash_map<int, CustomerData> entries;
hash_map<int, CustomerData>::const_iterator recordIter;
typedef pair<int, CustomerData> CustomerRecordEntry;

void GenerateCustomerList(const list<pair<int, int>>& cuslist, int logNum);

int main()
{
  list<pair<int, int>> log1, log2, log3;
  log1.push_back(make_pair(1,1));
  log1.push_back(make_pair(2,2));
  log1.push_back(make_pair(4,1));
  log1.push_back(make_pair(1,3));

  log2.push_back(make_pair(2,1));
  log2.push_back(make_pair(2,4));
  log2.push_back(make_pair(4,2));
  log2.push_back(make_pair(1,3));
  log2.push_back(make_pair(1,5));

  log3.push_back(make_pair(3,2));
  log3.push_back(make_pair(4,4));
  log3.push_back(make_pair(5,2));
  log3.push_back(make_pair(5,5));

  GenerateCustomerList(log1, 1);
  GenerateCustomerList(log2, 2);
  GenerateCustomerList(log3, 3);

  int cid = 0;
  cout << "Enter customer ID: " ;
  cin >> cid;

  recordIter = entries.find(cid);
  if(recordIter != entries.end())
  {
    CustomerData data = (CustomerData)recordIter->second;
    if(data.days.count() == DAYS_VISIT_COUNT && data.pages.size() == PAGE_VIEW_COUNT)
    {
      cout << "Customer visited on exactly 2 days and have 3 or more distinct page views."
        << endl;
    }
    else
    {
      cout <<
        "Customer didn't visited on exactly 2 days or have 3 or more distinct page views."
        << endl;
    }
  }
  else
    cerr << "Customer ID not found in logs." << endl;

  cout << endl;
  return 0;
}

void GenerateCustomerList(const list<pair<int, int>>& cuslist, int logNum)
{
  list<pair<int, int>>::const_iterator iter;
  for(iter = cuslist.begin(); iter != cuslist.end(); iter++)
  {
    recordIter = entries.find(iter->first);
    if(recordIter != entries.end())
    {
      CustomerData data = (CustomerData)recordIter->second;
      data.days.set((logNum-1), true);
      //Space optimization
      //Check if already have 3 distinct page view, no need to add more
      if(data.pages.size() < PAGE_VIEW_COUNT)
        data.pages.insert(iter->second);
      entries[recordIter->first] = data;
    }
    else
    {
      bitset<PAGE_VIEW_COUNT> days(string("000"));
      days.set((logNum-1), true);
      set<int> pages;
      pages.insert(iter->second);
      CustomerData data(days, pages);
      entries.insert(CustomerRecordEntry(iter->first, data));
    }
  }
}

Comments Closed

How to read/write from a file, like you are reading from the stdin/stdout?

May 12th, 2010 | by | technology

May
12

Using the freopen function you can read/write from a file, like you are reading from the standard input/output. freeopen first tries to close any file already associated with the stream given as third parameter and disassociates it. Then, whether that stream was successfuly closed or not, freopen opens the file whose name is passed in the first parameter, filename, and associates it with the specified stream just as fopen would do using the mode value specified as the second parameter.

If you had a program that normally would read from stdin, but instead you wanted it to read from a file. Instead of changing all your scanf()s to fscanf()s, you could simply reopen stdin on the file you wanted to read from.

The prototype of freopen is:

#include <cstdio>

FILE *freopen(const char *filename, const char *mode, FILE *stream);

Example:

#include <stdio.h>

int main(void)
{
    int i, i2;

    scanf("%d", &i); // read i from stdin

    // now change stdin to refer to a file instead of the keyboard
    freopen("someints.txt", "r", stdin);

    scanf("%d", &i2); // now this reads from the file "someints.txt"

    printf("Hello, world!\n"); // print to the screen

    // change stdout to go to a file instead of the terminal:
    freopen("output.txt", "w", stdout);

    printf("This goes to the file \"output.txt\"\n");

    // this is allowed on some systems--you can change the mode of a file:
    freopen(NULL, "wb", stdout); // change to "wb" instead of "w"

    return 0;
}

No Comments »

Controls Enable Disable Refactoring

December 26th, 2009 | by | technology

Dec
26

How many times we have written such code to enable/disable controls, based on some conditions:

if (string.IsNullOrEmpty(textBoxFind.Text))
{
  buttonFindNext.Enabled = false;
  buttonReplace.Enabled = false;
  buttonReplaceAll.Enabled = false;
}
else
{
  buttonFindNext.Enabled = true;
  if (string.IsNullOrEmpty(textBoxReplace.Text))
  {
    buttonReplace.Enabled = false;
    buttonReplaceAll.Enabled = false;
  }
  else
  {
    buttonReplace.Enabled = true;
    buttonReplaceAll.Enabled = true;
  }
}

When the same code can be expressed in a more clear and clean format:

bool isFindTextPresent = !String.IsNullOrEmpty(textBoxFind.Text);
bool isReplaceTextPresent = !String.IsNullOrEmpty(textBoxReplace.Text);
buttonFindNext.Enabled = isFindTextPresent;
buttonReplace.Enabled = (isFindTextPresent && isReplaceTextPresent);
buttonReplaceAll.Enabled = (isFindTextPresent && isReplaceTextPresent);

No Comments »

The power of refactoring?

December 24th, 2009 | by | technology

Dec
24

Check out this piece of code taken from CodeProject.

bool son; 

if (mShowShadow == false)
  son = false;
else
{
  if (DropShadowSupported() == false)
    son = false;
  else
  {
    son = true;
  }
} 

if (son)
{
  parameters.ClassStyle += CS_DROPSHADOW;
}

The code doesn’t made any sense to me, so I refactored and guess what the outcome:

if (mShowShadow && DropShadowSupported())
  parameters.ClassStyle += CS_DROPSHADOW;

No Comments »

XDocument can’t load a simple xml with version 1.1

November 26th, 2009 | by | technology

Nov
26

using System;
using System.Xml.Linq;

class Test
{
  static void Main(string[] args)
  {
    string xml = "<?xml version=\"1.1\" ?><root><sub /></root>";
    XDocument doc = XDocument.Parse(xml);
    Console.WriteLine(doc);
  }
}

 

Unhandled Exception:
  System.Xml.XmlException: Version number '1.1' is invalid. Line 1, position 16.
  at System.Xml.XmlTextReaderImpl.Throw(Exception e)
  at System.Xml.XmlTextReaderImpl.Throw(String res, String arg)
  at System.Xml.XmlTextReaderImpl.ParseXmlDeclaration(Boolean isTextDecl)
  at System.Xml.XmlTextReaderImpl.Read()
  at System.Xml.Linq.XDocument.Load(XmlReader reader, LoadOptions options)
  at System.Xml.Linq.XDocument.Parse(String text, LoadOptions options)
  at System.Xml.Linq.XDocument.Parse(String text)
  at Test.Main(String[] args)

No wonder, with this type of hardcoding values (e.g. version) and such poor quality of XML parsers used by Microsoft, Internet explorer can’t load a plain (‘hello world’ equivalent) XHTML page.

No Comments »

The Intelligent Smoker

November 17th, 2009 | by | technology

Nov
17

A person smokes cigarettes and leaves the lower portion (around 1/5) of it unburnt. He then combines the 5 residues of those cigarettes to create a new one for smoking.

If the person had initially 93 cigarettes, how many cigarettes did he actually smoked?

He will smoke 116 cigarettes.

#include <utility>
#include <iostream>

typedef std::pair<int,double> Cigarettes;
using namespace std;

#define PIECES_REQD_TO_CREATE_A_NEW_CIGARETTE 5

Cigarettes cigarette(Cigarettes count);

int main()
{
  int initialCount = 0;
  cout << "Enter the number of initial cigarettes: ";
  cin >> initialCount;
  Cigarettes count = make_pair(initialCount, 0.0);
  cout << "The person smoked " << cigarette(count).first << " number of cigarettes." << endl;
  return 0;
}

Cigarettes cigarette(Cigarettes count)
{
  if(count.first > 0)
  {
    Cigarettes tmp = make_pair(count.first/PIECES_REQD_TO_CREATE_A_NEW_CIGARETTE,
      count.second + ((count.first%PIECES_REQD_TO_CREATE_A_NEW_CIGARETTE)/
      (PIECES_REQD_TO_CREATE_A_NEW_CIGARETTE+0.0)));
    if(tmp.second >= 1.0)
    {
      tmp.first += 1;
      tmp.second -= 1;
    }
    tmp = cigarette(tmp);
    count.first += tmp.first;
    count.second = tmp.second;
  }
  return count;
}

No Comments »

Advanced STL

November 9th, 2009 | by | technology

Nov
09

Sample code to explain some advanced STL concepts.

//
// STL.cpp
// Sample code to explain some advanced STL concepts. This is a shameless
// copy of online materials in order to create a simple example program to
// explain the basics of STL.
//
// Topics covered:
// ostream_iterator, copy, deque, insert_iterator, front_inserter,
// back_inserter, accumulate, count, count_if, find, find_if, generate,
// generate_n, fill, fill_n, transform, negate, mismatch, search, equal,
// for_each, swap, sort, merge, binary_search, includes, ptr_fun, set_union,
// set_intersection, set_difference.
//
// Prerequisite:
// Basic STL concepts: vectors, maps, sets, iterators, algorithms
//
// Author:
// Priyank Bolia (priyank.co.in)
//
// License:
// Priyank Bolia does not hold any copyrights for this work
// and the rights still remains with the original authors, who had done all
// the hard work.
//
// References:
// sgi.com/tech/stl/swap.html, msdn.microsoft.com
//

#define _SECURE_SCL 0  // Disable visual Studio 2005 warnings

#include <iterator>
#include <deque>
#include <iostream>
#include <algorithm>
#include <numeric>
#include <functional>
#include <vector>

using namespace std;

// Creation of a user-defined function object
// that inherits from the unary_function base class
class greaterthan : unary_function<int, bool>
{
  int num;

public:
  greaterthan(int n) : num(n) {}

  result_type operator()(argument_type i)
  {
    return (result_type)(i > num);
  }
};

// return the next Fibonacci number in the Fibonacci series.
int Fibonacci(void)
{
  static int r;
  static int f1 = 0;
  static int f2 = 1;
  r = f1 + f2 ;
  f1 = f2 ;
  f2 = r ;
  return f1 ;
}

template<class T> struct print : public unary_function<T, void>
{
  print(ostream& out) : os(out), count(0) {}
  void operator() (T x) { os << x << ' '; ++count; }
  ostream& os;
  int count;
};

inline bool lt_nocase(char c1, char c2) { return tolower(c1) < tolower(c2); }

int main ()
{
  int arr[4] = { 3,4,7,8 };  // Initialize a deque using an array.

  // A deque is very much like a vector: like vector, it is a sequence that
  // supports random access to elements, const time insertion and
  // removal of elements at the end of the sequence, and linear time
  // insertion and removal of elements in the middle. The main way in which
  // deque differs from vector is that deque also supports constant
  // time insertion and removal of elements at the beginning of the sequence.
  // Additionally, deque does not have any member functions analogous to
  // vector's capacity() and reserve(), and does not provide any of the
  // guarantees on iterator validity that are associated with those member
  // functions.
  deque<int> d(arr+0, arr+4);

  cout << "Start with a deque: ";  // Output the original deque.

  // An ostream_iterator is an Output Iterator that performs formatted
  // output of objects of type T to a particular ostream. Note that all
  // of the restrictions of an Output Iterator must be obeyed, including
  // the restrictions on the ordering of operator* and operator++
  // operations.
  copy(d.begin(), d.end(), ostream_iterator<int>(cout," "));
  // OUTPUT: Start with a deque: 3 4 7 8

  // Insert into the middle.
  // Insert_iterator is an iterator adaptor that functions as an Output
  // Iterator: assignment through an insert_iterator inserts an object
  // into a Container. Specifically, if ii is an insert_iterator, then
  // ii keeps track of a Container c and an insertion point p; the
  // expression *ii = x performs the insertion c.insert(p, x).
  insert_iterator<deque<int> > ins(d, d.begin()+2);
  *ins = 5; *ins = 6;

  // Output the new deque.
  cout << endl << endl;
  cout << "Use an insert_iterator: ";

  // Copies elements from range [first, last) to the range
  // [result, result + (last - first)).  That is, it performs the
  // assignments *result = *first, *(result + 1) = *(first + 1), and so on.
  // Generally, for every integer n from 0 to last - first, copy performs
  // the assignment *(result + n) = *(first + n). Assignments are
  // performed in forward order, i.e. in order of increasing n.
  // The return value is result + (last - first)
  copy(d.begin(), d.end(), ostream_iterator<int>(cout," "));
  // OUTPUT: Use an insert_iterator: 3 4 5 6 7 8

  // A deque of four 1s.
  deque<int> d2(4, 1);

  // Insert d2 at front of d.
  // Front_insert_iterator is an iterator adaptor that functions as an
  // Output Iterator: assignment through a front_insert_iterator inserts
  // an object before the first element of a Front Insertion Sequence.
  copy(d2.begin(), d2.end(), front_inserter(d));

  // Output the new deque.
  cout << endl << endl;
  cout << "Use a front_inserter: ";
  copy(d.begin(), d.end(), ostream_iterator<int>(cout," "));
  // OUTPUT: Use a front_inserter: 1 1 1 1 3 4 5 6 7 8

  // Insert d2 at back of d.
  // Back_insert_iterator is an iterator adaptor that functions as an
  // Output Iterator: assignment through a back_insert_iterator inserts
  // an object after the last element of a Back Insertion Sequence.
  copy(d2.begin(), d2.end(), back_inserter(d));

  // Output the new deque.
  cout << endl << endl;
  cout << "Use a back_inserter: ";
  copy(d.begin(), d.end(), ostream_iterator<int>(cout," "));
  cout << endl << endl;
  // OUTPUT: Use a back_inserter: 1 1 1 1 3 4 5 6 7 8 1 1 1 1

  // Accumulate example
  int A[] = {1, 2, 3, 4, 5};
  const int N = sizeof(A) / sizeof(int);
  deque<int> a(A+0, A+N);

  // Adding the numbers
  // Accumulate is a generalization of summation: it computes the sum
  // (or some other binary operation) of init and all of the elements in
  // the range [first, last).
  cout << "The sum of ";
  copy(a.begin(), a.end()-1, ostream_iterator<int>(cout, " + "));
  cout << *(a.end()-1) << " is "
    << accumulate(a.begin(), a.end(), 0)
    << endl << endl;
  // OUTPUT: The sum of 1 + 2 + 3 + 4 + 5 is 15

  // Multiplying the numbers
  // Multiplies<T> is a function object. Specifically, it is an Adaptable
  // Binary Function. If f is an object of class multiplies<T> and x and y
  // are objects of class T, then f(x,y) returns x*y. Similarly, there is:
  // plus<T> (+), minus<T> (-), divides<T> (/), modulus<T> (%).
  cout << "The product of ";
  copy(a.begin(), a.end()-1, ostream_iterator<int>(cout, " + "));
  cout << *(a.end()-1) << " is "
    << accumulate(a.begin(), a.end(), 1, multiplies<int>())
    << endl << endl;
  // OUTPUT: The product of 1 * 2 * 3 * 4 * 5 is 120

  // Count finds the number of elements in [first, last) that are
  // equal to value.
  cout << "Number of ones: "
    << (int)count(A, A + N, 1)
    << endl << endl;
  // OUTPUT: Number of ones: 1

  // Count_if finds the number of elements in [first, last) that satisfy
  // the predicate pred.
  cout << "Number of elements greater than 3: "
    << (int)count_if(A, A + N, greaterthan(3))
    << endl << endl;
  // OUTPUT: Number of elements greater than 3: 2

  // find returns the first iterator i in the range [first, last) such
  // that *i == value.
  // Returns last if no such iterator exists.
  deque<int>::iterator find_result = find(a.begin(), a.end(), 2);
  cout << "Find whether 2 is present in A: " << *(find_result)
    << endl << endl;
  // OUTPUT: Find whether 2 is present in A: 2

  // find_if returns the first iterator i in the range [first, last)
  // such that pred(*i) is true.
  // Returns last if no such iterator exists.
  deque<int>::iterator find_if_result = find_if(a.begin(), a.end(),
    bind2nd(greater<int>(), 3));
  // Binder2nd is a function object adaptor: it is used to transform an
  // adaptable binary function into an adaptable unary function.
  // Specifically, if f is an object of class
  // binder2nd<AdaptableBinaryFunction>, then f(x) returns F(x, c),
  // where F is an object of class AdaptableBinaryFunction and where
  // c is a const. Both F and c are passed as arguments to
  // binder2nd's constructor.

  cout << "Find number greater than 3 in A: " << *(find_if_result)
    << " " << *(find_if_result++) << endl << endl;
  // OUTPUT: Find number greater than 3 in A: 5 4

  cout << "Fibonacci series: ";
  // The generate_n algorithm traverses the range [First, First + n),
  // assigning to each element the value returned by Gen.
  // The return value is first + n.
  generate_n(ostream_iterator<int>(cout, " "), 10, Fibonacci);
  cout << endl << endl;
  // OUTPUT: Fibonacci series: 1 1 2 3 5 8 13 21 34 55

  const int NUM = 10;
  vector<int> V1(NUM);
  vector<int> V2(NUM);

  // Generate assigns the result of invoking gen, a function object that
  // takes no arguments, to each element in the range [first, last).
  generate(V1.begin(), V1.end(), rand);

  // Fill assigns the value to every element in the range
  // [first, last). That is, for every iterator i in [first, last),
  // it performs the assignment *i = value.
  fill(V2.begin(), V2.end(), 0);

  // Fill_n assigns the value to every element in the range
  // [first, first+n). That is, for every iterator i in [first, first+n),
  // it performs the assignment *i = value.
  // The return value is first + n.
  fill_n(back_inserter(V2), 5, 42);

  // Transform performs an operation on objects.
  // It performs the operation op(*i1, *i2) for each iterator i1 in the
  // range [first1, last1) and assigns the result to *o, where i2 is the
  // corresponding iterator in the second input range and where o is the
  // corresponding output iterator. That is, for each n such that
  // 0 <= n < last1 - first1, it performs the assignment
  // *(result + n) = op(*(first1 + n), *(first2 + n). The return value is
  // result + (last1 - first1).
  transform(V1.begin(), V1.end(), V2.begin(), negate<int>());
  // If f is an object of class negate<T> and x is an object of class T,
  // then f(x) returns -x.

  cout << "Result of negate on randomly generated values: ";
  copy(V2.begin(), V2.end(), ostream_iterator<int>(cout, " "));
  cout << "\nThe last 42 were filled with fill_n function."
     << endl << endl;
  // OUTPUT: Result of negate on randomly generated values: -41 -18467
  // -6334 -26500 -19169 -1 5724 -11478 -29358 -26962 -24464 42 42 42 42 42
  // The last 42 were filled with fill_n function.

  // mismatch
  int A1[] = { 3, 1, 4, 1, 5, 9, 3 };
  int A2[] = { 3, 1, 4, 2, 8, 5, 7 };
  const int NMIS = sizeof(A1) / sizeof(int);

  // Mismatch finds the first position where the two ranges [first1, last1)
  // and [first2, first2 + (last1 - first1)) differ.
  pair<int*, int*> result = mismatch(A1, A1 + NMIS, A2);
  // Pair<T1,T2> is a heterogeneous pair: it holds one object of type T1
  // and one of type T2. A pair is much like a Container, in that it "owns"
  // its elements. It is not actually a model of Container, though, because
  // it does not support the sDarkorangedard methods (such as iterators)
  // for accessing the elements of a Container.
  cout << "The first mismatch is in position " << (int)(result.first - A1)
    << endl;
  cout << "Values are: " << *(result.first) << ", " << *(result.second)
    << endl << endl;
  // OUTPUT: The first mismatch is in position 3
  // Values are: 1, 2

  // search
  const char S1[] = "Hello, world!";
  const char S2[] = "world";
  const int N1 = sizeof(S1) - 1;
  const int N2 = sizeof(S2) - 1;

  // Search finds a subsequence within the range [first1, last1) that is
  // identical to [first2, last2) when compared element-by-element. It
  // returns an iterator pointing to the beginning of that subsequence,
  // or else last1 if no such subsequence exists
  const char* p = search(S1, S1 + N1, S2, S2 + N2);
  cout << "Found subsequence \"" << S2 << "\" at character " << (int)(p - S1)
    << " of sequence \"" << S1 << "\"." << endl << endl;
  // OUTPUT: Found subsequence "world" at character 7 of sequence
  // "Hello, world!".

  // equal
  int AE1[] = { 3, 1, 4, 1, 5, 9, 3 };
  int AE2[] = { 3, 1, 4, 2, 8, 5, 7 };
  const int NEQU = sizeof(AE1) / sizeof(int);

  // Equal returns true if the two ranges [first1, last1) and
  // [first2, first2 + (last1 - first1)) are identical when compared
  // element-by-element, and otherwise returns false.
  cout << "Result of comparison: " << equal(AE1, AE1 + NEQU, AE2)
    << endl << endl;
  // OUTPUT: Result of comparison: 0

  // for_each
  int AFOREACH[] = {1, 4, 2, 8, 5, 7};
  const int NFOREACH = sizeof(A) / sizeof(int);

  // For_each applies the function object f to each element in the range
  // [first, last); f's return value, if any, is ignored. Applications are
  // performed in forward order,  i.e. from first to last. For_each returns
  // the function object after it has been applied to each element.
  print<int> P = for_each(AFOREACH, AFOREACH + NFOREACH, print<int>(cout));
  cout << endl << P.count << " objects printed." << endl << endl;
  // OUTPUT: 1 4 2 8 5
  // 5 objects printed.

  cout << "Swapping contents of vector V2 to V1: ";
  // Swap Assigns the contents of a to b and the contents of b to a. This
  // is used as a primitive operation by many other algorithms.
  swap(V1, V2);
  copy(V1.begin(), V1.end(), ostream_iterator<int>(cout, " "));
  cout << endl << endl;
  // OUTPUT: Swapping contents of vector V2 to V1: -41 -18467 -6334 -26500
  // -19169 -15724 -1147 8 -29358 -26962 -24464 42 42 42 42 42

  // Sort sorts the elements in [first, last) into ascending order,
  // meaning that if i and j are any two valid iterators in [first, last)
  // such that i precedes j, then *j is not less than *i. Note: sort is
  // not guaranteed to be stable. That is, suppose that *i and *j are
  // equivalent: neither one is less than the other. It is not guaranteed
  // that the relative order of these two elements will be preserved by sort.
  cout << "Sorted array 1: ";
  sort(AE1, AE1 + NEQU);
  copy(AE1, AE1 + NEQU, ostream_iterator<int>(cout, " "));
  cout << endl << endl;
  // OUTPUT: Sorted array 1: 1 1 3 3 4 5 9
  cout << "Sorted array 2: ";
  sort(AE2, AE2 + NEQU);
  copy(AE2, AE2 + NEQU, ostream_iterator<int>(cout, " "));
  cout << endl << endl;
  // OUTPUT: Sorted array 2: 1 2 3 4 5 7 8

  // Merge combines two sorted ranges [first1, last1) and [first2, last2)
  // into a single sorted range. That is, it copies elements from
  // [first1, last1) and [first2, last2) into
  // [result, result + (last1 - first1) + (last2 - first2)) such that the
  // resulting range is in ascending order. Merge is stable, meaning both
  // that the relative order f elements within each input range is
  // preserved, and that for equivalent elements in both input ranges the
  // element from the first range precedes the element from the second.
  // The return value is result + (last1 - first1) + (last2 - first2).
  cout << "Merged sorted array: ";
  merge(AE1, AE1 + NEQU, AE2, AE2 + NEQU,
    ostream_iterator<int>(cout, " "));
  cout << endl << endl;
  // OUTPUT: Merged sorted array: 1 1 1 2 3 3 3 4 4 5 5 7 8 9

  // Binary_search is a version of binary search: it attempts to find the
  // element value in an ordered range [first, last) It returns true if
  // an element that is equivalent to value is present in [first, last)
  // and false if no such element exists.
  cout << "Searching for 7 in AE1: "
    << (binary_search(AE1, AE1 + NEQU, 7) ? "present" : "not present")
    << endl << endl;
  // OUTPUT: Searching for 7 in AE1: not present

  int AI1[] = { 1, 2, 3, 4, 5, 6, 7 };
  int AI2[] = { 1, 4, 7 };

  const int NI1 = sizeof(AI1) / sizeof(int);
  const int NI2 = sizeof(AI2) / sizeof(int);

  // Includes tests whether one sorted range includes another sorted
  // range. That is, it returns true if and only if, for every element
  // in [first2, last2), an equivalent element is also present
  // in [first1, last1). Both [first1, last1) and [first2, last2)
  // must be sorted in ascending order.
  cout << "AI2 contained in AI1: "
    << (includes(AI1, AI1 + NI1, AI2, AI2 + NI2) ? "true" : "false")
    << endl << endl;
  // OUTPUT: AI2 contained in AI1: true

  // Ptr_fun takes a function pointer as its argument and returns a
  // function pointer adaptor, a type of function object. It is actually
  // two different functions, not one (that is, the name ptr_fun is
  // overloaded). If its argument is of type Result (*)(Arg) then ptr_fun
  // creates a pointer_to_unary_function, and if its argument is of type
  // Result (*)(Arg1, Arg2) then ptr_fun creates a
  // pointer_to_binary_function.
  vector <char*> vec1;
  vector <char*>::iterator Iter1, RIter;

  vec1.push_back ( "Open" );
  vec1.push_back ( "up" );
  vec1.push_back ( "the" );
  vec1.push_back ( "pearly" );
  vec1.push_back ( "gates" );

  cout << "Original sequence contains: " ;
  for ( Iter1 = vec1.begin( ) ; Iter1 != vec1.end( ) ; Iter1++ )
    cout << *Iter1 << " ";
  cout << endl;
  // OUTPUT: Original sequence contains: Open up the pearly gates

  // To search the sequence for "pearly"
  // use a pointer_to_function conversion
  // find_if returns the first iterator i in the range [first, last)
  // such that pred(*i) is true.
  // Returns last if no such iterator exists.
  RIter = find_if( vec1.begin( ), vec1.end( ),
    not1 ( bind2nd (ptr_fun ( strcmp ), "pearly" ) ) );

  if ( RIter != vec1.end( ) )
  {
    cout << "The search for 'pearly' was successful.\n";
    cout << "The next character string is: "
      << *++RIter << "." << endl << endl;
  }
  // OUTPUT: The search for 'pearly' was successful.
  // The next character string is: gates.

  // Set_union constructs a sorted range that is the union of the sorted
  // ranges [first1, last1) and [first2, last2). The return value is the
  // end of the output range.
  int AS1[] = {1, 3, 5, 7, 9, 11};
  int AS2[] = {1, 1, 2, 3, 5, 8, 13};  

  const int SN1 = sizeof(AS1) / sizeof(int);
  const int SN2 = sizeof(AS2) / sizeof(int); 

  cout << "Union of AS1 and AS2: ";
  set_union(AS1, AS1 + SN1, AS2, AS2 + SN2,
    ostream_iterator<int>(cout, " "));
  cout << endl << endl;
  // OUTPUT: Union of AS1 and AS2: 1 1 2 3 5 7 8 9 11 13

  // Set_intersection constructs a sorted range that is the intersection
  // of the sorted ranges [first1, last1) and [first2, last2). The return
  // value is the end of the output range.
  char AS3[] = {'a', 'b', 'b', 'B', 'B', 'f', 'h', 'H'};
  char AS4[] = {'A', 'B', 'B', 'C', 'D', 'F', 'F', 'H' };
  const int SN3 = sizeof(AS3);
  const int SN4 = sizeof(AS4);

  cout << "Intersection of AS3 and AS4: ";
  set_intersection(AS3, AS3 + SN3, AS4, AS4 + SN4,
    ostream_iterator<char>(cout, " "), lt_nocase);
  cout << endl << endl;
  // OUTPUT: Intersection of AS3 and AS4: a b b f h

  // Set_difference constructs a sorted range that is the set difference
  // of the sorted ranges [first1, last1) and [first2, last2). The return
  // value is the end of the output range.
  cout << "Difference of AS3 and AS4: ";
  set_difference(AS3, AS3 + SN3, AS4, AS4 + SN4,
    ostream_iterator<char>(cout, " "), lt_nocase);
  cout << endl << endl;
  // OUTPUT: Difference of AS3 and AS4: B B H

  return 0;
}

No Comments »

Programming Puzzle: Train Timetable

November 6th, 2009 | by | technology

Nov
06

A train line has two stations on it, A and B. Trains can take trips from A to B or from B to A multiple times during a day. When a train arrives at B from A (or arrives at A from B), it needs a certain amount of time before it is ready to take the return journey – this is the turnaround time. For example, if a train arrives at
12:00 and the turnaround time is 0 minutes, it can leave immediately, at 12:00.

A train timetable specifies departure and arrival time of all trips between A and B. The train company needs to know how many trains have to start the day at A and B in order to make the timetable work: whenever a train is supposed to leave A or B, there must actually be one there ready to go. There are passing sections on the track, so trains don’t necessarily arrive in the same order that they leave. Trains may not travel on trips that do not appear on the schedule.

Input:

The first line of input gives the number of cases, N. N test cases follow.

Each case contains a number of lines. The first line is the turnaround time, T, in minutes. The next line has two numbers on it, NA and NB. NA is the number of trips from A to B, and NB is the number of trips from B to A. Then there are NA lines giving the details of the trips from A to B.

Each line contains two fields, giving the HH:MM departure and arrival time for that trip. The departure time for each trip will be earlier than the arrival time. All arrivals and departures occur on the same day. The trips may appear in any order – they are not necessarily sorted by time. The hour and minute values are both two digits, zero-padded, and are on a 24-hour clock (00:00 through 23:59).

After these NA lines, there are NB lines giving the departure and arrival times for the trips from B to A.

Output:

For each test case, output one line containing “Case #x: ” followed by the number of trains that must start at A and the number of trains that must start at B.

Limits:

1 <= N <= 100

Small dataset:

0 <= NA, NB <= 20
0 <= T <= 5

Large dataset:

0 <= NA, NB <= 100
0 <= T <= 60

Input
———–
2
5
3 2
09:00 12:00
10:00 13:00
11:00 12:30
12:02 15:00
09:00 10:30
2
2 0
09:00 09:01
12:00 12:02

Output
————
Case #1: 2 2
Case #2: 2 0

// Train Timetable
// Author: Priyank Bolia <http://priyank.co.in>
// Date: 17th July, 2008

#include <iostream>
#include <fstream>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <stdlib.h>

using namespace std;

typedef pair<int, int> TrainTime;
typedef vector<int> Time;
typedef vector<pair<int, int>> TimeTable;

std::vector<std::string> tokenize_str(const std::string &str,
      const std::string &delims);
bool value_comparer(const std::pair<int, int> &lhs,
      const std::pair<int, int> &rhs);
TrainTime ConvertToTimeTableEntry(string &s, int turnAround);
size_t TrainsNeeded(TimeTable &a, TimeTable &b);

int main()
{
  ifstream inputFile ("B-large.in");
  ofstream outputFile ("output.in");
  if(!inputFile.is_open())
    return 0;
  if(!outputFile.is_open())
    return 0;
  int totalCases = 0;
  inputFile >> totalCases;
  for (int i=0; i < totalCases; ++i)
  {
    int turnaroundTime = 0;
    int trainsFromA = 0;
    int trainsFromB = 0;
    TimeTable stationA;
    TimeTable stationB;
    string line;
    inputFile >> turnaroundTime;
    getline(inputFile, line);  //Get to next line
    inputFile >> trainsFromA;
    inputFile >> trainsFromB;
    getline(inputFile, line);  //Get to next line
    for (int j=0; j < trainsFromA; ++j)
    {
      getline(inputFile, line);
      stationA.push_back(ConvertToTimeTableEntry(line, turnaroundTime));
    }
    for (int j=0; j < trainsFromB; ++j)
    {
      getline(inputFile, line);
      stationB.push_back(ConvertToTimeTableEntry(line, turnaroundTime));
    }
    std::sort(stationA.begin(), stationA.end(), value_comparer);
    std::sort(stationB.begin(), stationB.end(), value_comparer);
    outputFile << "Case #" << (i+1) << ": " << TrainsNeeded(stationA, stationB) << " "
      << TrainsNeeded(stationB, stationA) << endl;
  }
  inputFile.close();
  outputFile.close();
  return 0;
}

size_t TrainsNeeded(TimeTable &a, TimeTable &b)
{
  size_t trainsNeeded = 0;
  Time trainsArrivingFromB;
  for(TimeTable::const_iterator iter = b.begin(); iter != b.end(); ++iter)
  {
    trainsArrivingFromB.push_back((*iter).second);
  }
  std::sort(trainsArrivingFromB.begin(), trainsArrivingFromB.end(), less<int>());
  size_t indexB = 0;
  if(trainsArrivingFromB.size() == 0)
  {
    trainsNeeded = (size_t)a.size();
  }
  else
  {
    for(TimeTable::const_iterator iter = a.begin(); iter != a.end(); ++iter)
    {
      if(indexB < trainsArrivingFromB.size() && (*iter).first < trainsArrivingFromB[indexB])
        ++trainsNeeded;
      else if(indexB == trainsArrivingFromB.size())
        ++trainsNeeded;
      else
        ++indexB;
    }
  }
  return trainsNeeded;
}

bool value_comparer(const std::pair<int, int> &lhs,
      const std::pair<int, int> &rhs)
{
  return lhs.first < rhs.first;
}

TrainTime ConvertToTimeTableEntry(string &s, int turnAround)
{
  vector<string> timing(tokenize_str(s, " "));
  vector<string> startTime(tokenize_str(timing[0], ":"));
  vector<string> finishTime(tokenize_str(timing[1], ":"));
  int startAtMin = (atoi(startTime[0].c_str())*60) + atoi(startTime[1].c_str());
  int finishAtMin = (atoi(finishTime[0].c_str())*60) + atoi(finishTime[1].c_str());
  return make_pair<int, int>(startAtMin, finishAtMin+turnAround);
}

std::vector<std::string> tokenize_str(const std::string &str,
      const std::string &delims)
{
  using namespace std;
  // Skip delims at beginning, find start of first token
  string::size_type lastPos = str.find_first_not_of(delims, 0);
  // Find next delimiter @ end of token
  string::size_type pos     = str.find_first_of(delims, lastPos);

  // output vector
  vector<string> tokens;

  while (string::npos != pos || string::npos != lastPos)
  {
    // Found a token, add it to the vector.
    tokens.push_back(str.substr(lastPos, pos - lastPos));
    // Skip delims.  Note the "not_of". this is beginning of token
    lastPos = str.find_first_not_of(delims, pos);
    // Find next delimiter at end of token.
    pos     = str.find_first_of(delims, lastPos);
  }

  return tokens;
}

No Comments »

Programming Puzzle: Search Engine

November 6th, 2009 | by | technology

Nov
06

The urban legend goes that if you go to the Google homepage and search for “Google”, the universe will implode. We have a secret to share… It is true! Please don’t try it, or tell anyone. All right, maybe not. We are just kidding. The same is not true for a universe far far away. In that universe, if you search on any search engine for that search engine’s name, the universe does implode! To combat this, people came up with an interesting solution. All queries are pooled together. They are passed to a central system that decides which query goes to which search engine. The central system sends a series of queries to one search engine, and can switch to another at any time. Queries must be processed in the order they’re received. The central system must never send a query to a search engine whose name matches the query. In order to reduce costs, the number of switches should be minimized. Your task is to tell us how many times the central system will have to switch between search engines, assuming that we program it optimally.

Input:

The first line of the input file contains the number of cases, N. N test cases follow. Each case starts with the number S — the number of search engines. The next S lines each contain the name of a search engine. Each search engine name is no more than one hundred characters long and contains only uppercase letters, lowercase letters, spaces, and numbers. There will not be two search engines with the same name. The following line contains a number Q — the number of incoming queries. The next Q lines will each contain a query. Each query will be the name of a search engine in the case.

Output:

For each input case, you should output:
Case #X: Y
where X is the number of the test case and Y is the number of search engine switches. Do not count the initial choice of a search engine as a switch.

Limits:

0 < N <= 20

Small dataset:

2 <= S <= 10
0 <= Q <= 100

Large dataset:

2 <= S <= 100
0 <= Q <= 1000

Input
———
2
5
Yeehaw
NSM
Dont Ask
B9
Googol
10
Yeehaw
Yeehaw
Googol
B9
Googol
NSM
B9
NSM
Dont Ask
Googol
5
Yeehaw
NSM
Dont Ask
B9
Googol
7
Googol
Dont Ask
NSM
NSM
Yeehaw
Yeehaw
Googol

Output
———–
Case #1: 1
Case #2: 0

// Saving the Universe
// Author: Priyank Bolia <http://priyank.co.in>
// Date: 17th July, 2008

#include <iostream>
#include <fstream>
#include <algorithm>
#include <vector>
#include <string>
#include <map>

using namespace std;

bool value_comparer(const std::pair<std::string, size_t> &lhs,
        const std::pair<std::string, size_t> &rhs);
int SearchCount(vector<string>::iterator &enginesStart, vector<string>::iterator &enginesEnd,
      vector<string>::iterator &inputsStart, vector<string>::iterator &inputsEnd);

int main()
{
  ifstream inputFile ("A-large.in");
  ofstream outputFile ("output.in");
  if(!inputFile.is_open())
    return 0;
  if(!outputFile.is_open())
    return 0;
  int totalCases = 0;
  inputFile >> totalCases;
  for (int i=0; i < totalCases; ++i)
  {
    int searchEnginesCount = 0;
    int searchInputsCounts = 0;
    vector<string> searchEngines;
    vector<string> searchInputs;
    string line;
    inputFile >> searchEnginesCount;
    getline(inputFile, line);  //Get to next line
    for (int j=0; j < searchEnginesCount; ++j)
    {
      getline(inputFile, line);
      searchEngines.push_back(line);
    }
    inputFile >> searchInputsCounts;
    getline(inputFile, line);  //Get to next line
    for (int j=0; j < searchInputsCounts; ++j)
    {
      getline(inputFile, line);
      searchInputs.push_back(line);
    }
    int minSearch = SearchCount(searchEngines.begin(), searchEngines.end(),
      searchInputs.begin(), searchInputs.end());
    if(minSearch <= 0)
      minSearch = 1;
    outputFile << "Case #" << (i+1) << ": " << (minSearch-1) << endl;
  }
  inputFile.close();
  outputFile.close();
  return 0;
}

int SearchCount(vector<string>::iterator &enginesStart, vector<string>::iterator &enginesEnd,
      vector<string>::iterator &inputsStart, vector<string>::iterator &inputsEnd)
{
  map<string, size_t> maxSearch;
  if(distance(inputsStart, inputsEnd) <= 0)
    return 0;
  for(vector<string>::iterator iter = enginesStart; iter != enginesEnd; ++iter)
  {
    maxSearch[*iter] = distance(inputsStart, find(inputsStart, inputsEnd, *iter));
  }
  map<string, size_t>::const_iterator searchEngine =
    std::max_element(maxSearch.begin(), maxSearch.end(), value_comparer);
  return 1 + SearchCount(enginesStart, enginesEnd,
    (inputsStart+searchEngine->second), inputsEnd);
}

bool value_comparer(const std::pair<std::string, size_t> &lhs,
      const std::pair<std::string, size_t> &rhs)
{
  return lhs.second < rhs.second;
}

No Comments »

Detect & Install .NET 3.5 Framework using Inno Setup.

November 6th, 2009 | by | technology

Nov
06

In this article, we would see how to detect whether the .NET Framework is present or not, and how to install the .NET Framework automatically from the internet (Microsoft Website), if its already not present. The installation won’t continue, until the .NET Framework is installed. This article is basically a modification of the script at http://www.blackhillsoftware.com/blog/2006/06/26/using-innosetup-with-the-dotnet-framework/ and uses information from the Microsoft .NET Framework 3.5 Deployment Guide for Application Developers, to detect the .NET Framework 3.5 version.

Below is the INNO Setup script to detect and install the .NET 3.5 Framework. If you want some other version of .NET Framework, to be detected and installed automatically, just change the registry values to search and the dotnetRedistURL value to download that .NET Framework. To know about the exact registry values and keys to be used for detection of a particular version of .NET, you can read the article: Using managed code to detect what .NET Framework versions and service packs are installed.

 

Framework Version Registry Key
.NET Framework v1.1 HKLM\Software\Microsoft\NET Framework Setup\NDP\v1.1.4322\Install
.NET Framework v2.0 HKLM\Software\Microsoft\NET Framework Setup\NDP\v2.0.50727\Install
.NET Framework v3.5 HKLM\Software\Microsoft\NET Framework Setup\NDP\v3.5\Install

All of these values are a DWord value, so if it is present and set to 1, then that version of the Framework is installed.

 

Framework Version Download URL
.NET Framework v1.1 http://download.microsoft.com/download/a/a/c/aac39226-8825-44ce-90e3-bf8203e74006/dotnetfx.exe
.NET Framework v2.0 http://download.microsoft.com/download/5/6/7/567758a3-759e-473e-bf8f-52154438565a/dotnetfx.exe
.NET Framework v3.5 http://download.microsoft.com/download/7/0/3/703455ee-a747-4cc8-bd3e-98a615c3aedb/dotNetFx35setup.exe

Please note that these are temporary download URL and subject to change by Microsoft, also these download are for normal Windows 32 bit architecture.

[_ISTool]
EnableISX=true

[Files]
Source: C:\Program Files\ISTool\isxdl.dll; Flags: dontcopy

[Code]
var
 dotnetRedistPath: string;
 downloadNeeded: boolean;
 dotNetNeeded: boolean;
 memoDependenciesNeeded: string;

procedure isxdl_AddFile(URL, Filename: PChar);
external 'isxdl_AddFile@files:isxdl.dll stdcall';
function isxdl_DownloadFiles(hWnd: Integer): Integer;
external 'isxdl_DownloadFiles@files:isxdl.dll stdcall';
function isxdl_SetOption(Option, Value: PChar): Integer;
external 'isxdl_SetOption@files:isxdl.dll stdcall';

const
  dotnetRedistURL = 'http://download.microsoft.com/download/7/0/3/703455ee-a747-4cc8-bd3e-98a615c3aedb/dotNetFx35setup.exe';

function InitializeSetup(): Boolean;
var
  IsInstalled: Cardinal;
begin
  Result := true;
  dotNetNeeded := true;

  // Check for required netfx installation
  if(Is64BitInstallMode()) then begin
   if (RegValueExists(HKLM, 'SOFTWARE\Wow6432Node\Microsoft\NET Framework Setup\NDP\v3.5', 'Install')) then begin
    RegQueryDWordValue(HKLM, 'SOFTWARE\Wow6432Node\Microsoft\NET Framework Setup\NDP\v3.5', 'Install', IsInstalled);
    if(IsInstalled = 1) then begin
     dotNetNeeded := false;
     downloadNeeded := false;
    end;
   end;
  end
  else begin
   if (RegValueExists(HKLM, 'SOFTWARE\Microsoft\NET Framework Setup\NDP\v3.5', 'Install')) then begin
    RegQueryDWordValue(HKLM, 'SOFTWARE\Microsoft\NET Framework Setup\NDP\v3.5', 'Install', IsInstalled);
    if(IsInstalled = 1) then begin
     dotNetNeeded := false;
     downloadNeeded := false;
    end;
   end;
  end;

  if(dotNetNeeded) then begin
   if (not IsAdminLoggedOn()) then begin
    MsgBox('My Application needs the Microsoft .NET 3.5 Framework to be installed by an Administrator.', mbError, MB_OK);
    Result := false;
   end
   else begin
    dotnetRedistPath := ExpandConstant('{src}\dotnetfx.exe');
    if not FileExists(dotnetRedistPath) then begin
     dotnetRedistPath := ExpandConstant('{tmp}\dotnetfx.exe');
     if not FileExists(dotnetRedistPath) then begin
      isxdl_AddFile(dotnetRedistURL, dotnetRedistPath);
      downloadNeeded := true;
     end;
    end;
   end;
  end;
end;

function NextButtonClick(CurPage: Integer): Boolean;
var
  hWnd: Integer;
  ResultCode: Integer;
begin
  Result := true;

  if CurPage = wpReady then begin
  hWnd := StrToInt(ExpandConstant('{wizardhwnd}'));

  // don't try to init isxdl if it's not needed because it will error on < ie 3
  if (downloadNeeded) then begin
   isxdl_SetOption('label', 'Downloading Microsoft .NET 3.5 Framework');
   isxdl_SetOption('description', 'My Application needs to install the Microsoft .NET 3.5 Framework. Please wait while setup is downloading extra files to your computer.');
   if isxdl_DownloadFiles(hWnd) = 0 then Result := false;
   end;
   if (Result = true) and (dotNetNeeded = true) then begin
    if Exec(ExpandConstant(dotnetRedistPath), '/q /norestart', '', SW_SHOW, ewWaitUntilTerminated, ResultCode) then begin
     // handle success if necessary; ResultCode contains the exit code
     if not (ResultCode = 0) then begin
      Result := false;
     end;
    end
    else begin
     // handle failure if necessary; ResultCode contains the error code
     Result := false;
    end;
   end;
  end;
end;

No Comments »