/*
         *  The problem of scheduling unit-time tasks with deadlines and penalities for a single processor has following inputs
         *  S={a1,a2,...,an} of n unit-time task.
         *  A unit-time task requires exactly 1 unit of time to complete
         *  deadlines d1,d2,...,dn, 1<=di<=n
         *  penalities w1,w2,...,wn.
         *  A penality wi is incurred if task ai is not finished by time di, and no penality if task finishes at deadline
         *  The problem is to find a schedule for S that minimizes the total penalty incurred for missed deadlines
         *
         *  Complexety: O(n*log(n))
         */
        public static List <Tuple <Sequencing_Job, bool> > FindSequence3(Sequencing_Job[] jobs)
        {
            List <Tuple <Sequencing_Job, bool> > sequence = new List <Tuple <Sequencing_Job, bool> >();

            if (jobs.Length <= 0)
            {
                return(sequence);
            }

            Array.Sort(jobs, new Sequencing_ReverseComparerPenalty());

            int maxDeadline = Int32.MinValue;

            foreach (Sequencing_Job job in jobs)
            {
                if (job.Deadline > maxDeadline)
                {
                    maxDeadline = job.Deadline;
                }
            }

            Sequencing_DisjointSet disjointSet = new Sequencing_DisjointSet(maxDeadline);
            List <Sequencing_Job>  penalised   = new List <Sequencing_Job>();

            Sequencing_Job[] tmpSequence = new Sequencing_Job[jobs.Length];
            foreach (Sequencing_Job job in jobs)
            {
                int slot = disjointSet.Find(job.Deadline);

                if (slot > 0)
                {
                    disjointSet.Merge(disjointSet.Find(slot - 1), slot);
                    tmpSequence[slot - 1] = job;
                }
                else
                {
                    penalised.Add(job);
                }
            }

            foreach (Sequencing_Job job in tmpSequence)
            {
                if (job != null)
                {
                    sequence.Add(new Tuple <Sequencing_Job, bool>(job, false));
                }
            }

            foreach (Sequencing_Job job in penalised)
            {
                sequence.Add(new Tuple <Sequencing_Job, bool>(job, true));
            }

            return(sequence);
        }
        /*
         *  Given a set of n jobs where each job i has a deadline di >=1 and profit pi>=0.
         *  Only one job can be scheduled at a time. Each job takes 1 unit of time to complete.
         *  We earn the profit if and only if the job is completed by its deadline.
         *  The task is to find the subset of jobs that maximizes profit.
         *
         *  Complexety: O(n*log(n))
         */
        public static List <Sequencing_Job> FindSequence2(Sequencing_Job[] jobs)
        {
            List <Sequencing_Job> jobSequence = new List <Sequencing_Job>();

            if (jobs.Length <= 0)
            {
                return(jobSequence);
            }

            Array.Sort(jobs, new Sequencing_ReverseComparerProfit());

            int maxDeadline = Int32.MinValue;

            foreach (Sequencing_Job job in jobs)
            {
                if (job.Deadline > maxDeadline)
                {
                    maxDeadline = job.Deadline;
                }
            }

            Sequencing_DisjointSet disjointSet = new Sequencing_DisjointSet(maxDeadline);

            Sequencing_Job[] results = new Sequencing_Job[maxDeadline + 1];

            for (int i = 0; i < jobs.Length; i++)
            {
                int slot = disjointSet.Find(jobs[i].Deadline);

                if (slot > 0)
                {
                    int parentSlot = disjointSet.Find(slot - 1);
                    disjointSet.Merge(parentSlot, slot);
                    results[slot] = jobs[i];
                }
            }

            foreach (Sequencing_Job job in results)
            {
                if (job != null)
                {
                    jobSequence.Add(job);
                }
            }

            return(jobSequence);
        }