Online Judge Solutions

Friday, May 10, 2013

Score of the Racers

This problem was discussed at http://www.mitbbs.com/article_t/JobHunting/32401359.html.

The Problem: A bunch of racers, each one has start time and end time.  Calculate each racer's score based on the following rule:
  
    score = The number of racers who started after and finished earlier than current racer.

Note: There is no duplicated start time or end time.

 
Let's start defining the Racer as following (in C#):
class Racer
{
     public Racer(int id, int start, int end)
   { 
      Id = id;
      Start = start;
      End = end;
      StartRank = 0;
      Score = 0;
   }
   // Id of the Racer
   public int Id { get; set; }
   // Start time
   public int Start { get; set; }
   // Finish time
   public int End { get; set; }
   // The number of racers started after and finished before current racer.
   public int Score { get; set; }
   // The number of racers started before current racer
   public int StartRank { get; set; }
}

The Algorithm:

1. Sort the Racers based on Start time.
After this sort, the StartRank is assigned to the Racers.
2.Sort the Racers based on End time in ascending order.
In other word, racers finished earlier will be processed earlier in step 3. 
3.The heart of this algorithm. Initialize an empty List called RanksList. 
For each Racer ordered by the End time in 2,
  a. The score of current racer is the number of racers who start later(StartRank is higher than current Racer's StartRank) and finished earlier(StartRank already in RanksList).
  b. Insert current Racer's StartRank into the RanksList so that all the values in RanksList are ordered ascendingly.

step 3. can be done efficiently by leveraging following feature of List<T>.BinarySearch Method 

"If the List<T> does not contain the specified value, the method returns a negative integer. You can apply the bitwise complement operation (~) to this negative integer to get the index of the first element that is larger than the search value. When inserting the value into the List<T>, this index should be used as the insertion point to maintain the sort order.
This method is an O(log n) operation, where n is the number of elements in the range."
http://msdn.microsoft.com/en-us/library/w4e7fxsh.aspx
Implementation 
static void RankRacers(Racer[] racers)
{
  Array.Sort<Racer>(racers, (a, b) => a.Start - b.Start);
  for (int i = 0; i < racers.Length; ++i)
  {
     racers[i].StartRank = i;
  }   
  Aray.Sort<Racer>(racers, (a, b) => a.End - b.End);   
  List<int> StartRanks = new List<int>();
  for (int i = 0; i < racers.Length; ++i)
  { 
    racers[i].Score = BinarySearchInsert(StartRanks, racers[i].StartRank);
  }
}          
static int BinarySearchInsert(List<int> processedRanks, int startRank)
{
   int index = processedRanks.BinarySearch(startRank);
   index = (index < 0) ? ~index : index;
   int score = processedRanks.Count - index;
   processedRanks.Insert(index, startRank);  
  
   return score;        
} 

Test code:
static void PrintRacerScores(Racer[] racers)
{
   foreach (Racer racer in racers)
   {     
      Console.WriteLine("Racer - " + racer.Id);
      Console.WriteLine("Start - " + racer.Start);
      Console.WriteLine("End - " + racer.End);      Console.WriteLine("Score - " + racer.Score); 
      Console.WriteLine();
    }
} 

static void Main(string[] args)
{
   Racer[] racers = new Racer[] {
       new Racer(0, 1, 100),
       new Racer(1, 2, 10),
       new Racer(2, 3, 4),
       new Racer(3, 5, 6),
   }; 
   RankRacers(racers);   Array.Sort<Racer>(racers, (a, b) => a.Id - b.Id);
   PrintRacerScores(racers);
} 

Sample Output: 
Racer - 0
Start - 1
End - 100
Score - 3

Racer - 1
Start - 2
End - 10
Score - 2

Racer - 2
Start - 3
End - 4
Score - 0

Racer - 3
Start - 5
End - 6
Score - 0 

No comments:

Post a Comment