How to find height of BST iteratively? - c#

public void HeightIterative()
{
int counter = 0;
int counter2 = 0;
TreeNode current=root;
if(current != null)
{
while(current.LeftNode!=null)
{
counter++;
current = current.LeftNode;
}
while(current.RightNode!=null)
{
counter2++;
current = current.RightNode;
}
}
int res = 1+Math.Max(counter, counter2);
Console.WriteLine("The Height Of Tree Is: "+res);
}
I wrote iterative method, to calculate height of tree. but in some cases its not working properly. As in case:
10
1
2
3
4
5
18
17
16
15
14
13
what's the problem. according to this sequence height of tree is 6 where as my code is showing 5.

You are using two loops, but each loop investigated only oneside of node, but each node in tree has two sides you should investigate it all. You can do it through recursion call.
private int GetLen(TreeNode node)
{
var result = 0;
if(node != null)
{
result = Math.Max(GetLen(node.LeftNode), GetLen(node.RightNode)) + 1;
}
return result;
}
public void HeightIterative()
{
int res = GetLen(root);
Console.WriteLine("The Height Of Tree Is: "+res);
}
Iterative version:
private class NodeInfo
{
public NodeInfo(TreeNode node, int len)
{
Node = node;
Len = len;
}
public TreeNode Node {get; private set;}
public int Len {get; private set;}
}
public void HeightIterative()
{
int maxLen = 0;
var queue = new Queue<NodeInfo>();
queue.Enqueue(new NodeInfo(root, 1));
while (queue.Count > 0)
{
var item = queue.Dequeue();
var current = item.Node;
var currentLen = item.Len;
if (current.LeftNode != null)
{
queue.Enqueue(new NodeInfo(current.LeftNode, currentLen + 1));
}
if (current.RightNode != null)
{
queue.Enqueue(new NodeInfo(current.RightNode, currentLen + 1));
}
if (currentLen > maxLen)
{
maxLen = currentLen;
}
}
Console.WriteLine("The Height Of Tree Is: " + maxLen);
}

There is a way that does not require any extra space except the queue for storing the nodes.
Add child nodes of a current element and remember size of the queue.
Let each dequeue call decrement the counter
When counter reaches zero that means we are done with current level.
Repeat and count number of times counter reaches zero - this is the depth/height of the tree
Code goes like this :
public int treeDepth(Node root){
int height = 0;
int counterNodesInLevel = 1;
if(root!=null)
{
Queue<Node> queue=new Queue<Node>()
queue.enqueue(root);
while (!queue.isEmpty()){
Node current = queue.dequeue();
counterNodesInLevel -= 1;
if(current.left!=null){
queue.enqueue(current.left)
}
if(current.right!=null){
queue.enqueue(current.right)
}
if (counterNodesInLevel == 0){
height += 1;
counterNodesInLevel = queue.Size();
}
}
}
return height;
}
Time complexity is O(N), space complexity is O(N)

The problem:
You are finding the depth of the left-most node in the first loop, and the right-most in the second, and never interrogating any node that involves going down to the left AND the right.
A solution:
Have a single loop that drills down the left nodes, but adds each right node that it 'skips' into a queue. When you run out of left nodes, pop-off a node form your queue and continue on until the queue becomes empty. You'll need to store the height of each node you put in the queue with that node.

public int Height()
{
int result = GetMaxHeight(this.Root,0);
return result;
}
private int GetMaxHeight(Node<T> node,int count)
{
int leftMax = 0, rightMax = 0;
if (node.Left != null)
{
leftMax = GetMaxHeight(node.Left, count+1);
}
if (node.Right != null)
{
rightMax = GetMaxHeight(node.Right, count + 1);
}
if(node.Left==null && node.Right == null)
{
return count;
}
return Math.Max(leftMax,rightMax);
}

Related

How to add array values to equal a number, or fail if values in array wont work

I am trying to build a calculator that will tell me what "steps" are needed to stack up to a given value. Using only that "steps" available in the array.
Example:
decimal[] blocks {.05, .100, .150, .200, .250}
goal = .550m
result = .100, .200, .250
I have tried using nested if statements and array find/last with not much luck.
I can get a match if the goal is an exact match, or will match with two of them stacked. I can't get it to work for the max(.750).
This is what I have so far:
code:
string result = "nope";
decimal goal = 3.264m;
decimal[] DAStep = new decimal[10];
decimal temp = Array.Find(GaugeBlockArray, element => element.Equals(goal));
if (temp != 0m)
{
DAStep[0] = Array.Find(GaugeBlockArray, element => element.Equals(temp));
result = DAStep[0].ToString();
}
else
{
DAStep[0] = GaugeBlockArray.Last(element => element <= goal); ;
decimal remaining;
remaining = goal - DAStep[0];
while (remaining != 0m)
{
DAStep[1] = GaugeBlockArray.Last(element => element <= remaining);
if (DAStep[1] != remaining)
{
DAStep[2] = GaugeBlockArray.Last(element => element <= (DAStep[1] - .0001m));
if (DAStep[2] == 0) { DAStep[1] = DAStep[2]; }
}
}
}
GaugeBlockArray contains an array of 72 different elements from .05 to 4.0. And, I can only use each block once.
edit:
I guess more detail on the array contents may help getting to a solution.
GaugeBlockArray:
.05
.100
.1001
.1002
.1003
.1004
.1005
.1006
.1007
.1008
.1009
.110
.111
.112
.113
.114
.115
.116
.117
.118
.119
.120
.121
.122
.123
.124
.125
.126
.127
.128
.129
.130
.131
.132
.133
.134
.135
.136
.137
.138
.139
.140
.141
.142
.143
.144
.145
.146
.147
.148
.149
.150
.200
.250
.300
.350
.400
.450
.500
.550
.600
.650
.700
.750
.800
.850
.900
.950
1.000
2.000
3.000
4.000
Many thanks to #GeorgPatscheider for getting me pointed in the right direction!
This is my final working result:
public static void CountSum(decimal[] DNumbers, decimal Dsum)
{
foreach (Window window in Application.Current.Windows)
{
if (window.GetType() == typeof(MetTracker.GaugeCalc))
{
(window as MetTracker.GaugeCalc).CalculateBtn.Content = "working...";
}
}
DNumbers = Array.ConvertAll(DNumbers, element => 10000m * element);
string TempString = GetSettingsStrings("GBCMaxStep"); // only used to initialize max step value
Dsum = Dsum * 10000m;
Int32 Isum = Convert.ToInt32(Dsum);
Int32[] INumbers = Array.ConvertAll(DNumbers, element => (Int32)element);
// int result = 0;
GetmNumberOfSubsets(INumbers, Isum);
success = false;
return;
}
private static void GetmNumberOfSubsets(Int32[] numbers, Int32 Isum)
{
set = numbers;
sum = Isum;
FindSubsetSum();
}
//-------------------------------------------------------------
static Int32[] set;
static Int32[] subSetIndexes;
static Int32 sum;
static Int32 numberOfSubsetSums;
static bool success = false;
static List<Int32> ResultSet = new List<Int32>();
static List<string> results = new List<string>();//------------------------------------------------------------
/*
Method: FindSubsetSum()
*/
private static void FindSubsetSum()
{
numberOfSubsetSums = 0;
Int32 numberOfElements = set.Length;
FindPowerSet(numberOfElements);
}
//-------------------------------------------------------------
/*
Method: FindPowerSet(int n, int k)
*/
private static void FindPowerSet(Int32 n)
{
// Super set - all sets with size: 0, 1, ..., n - 1
for (Int32 k = 0; k <= n - 1; k++)
{
subSetIndexes = new Int32[k];
CombinationsNoRepetition(k, 0, n - 1);
if(subSetIndexes.Length >= GBC_MaxStepSetting) {
break; }
}
if (numberOfSubsetSums == 0)
{
MessageBox.Show("No subsets with wanted sum exist.");
}
}
//-------------------------------------------------------------
/*
Method: CombinationsNoRepetition(int k, int iBegin, int iEnd);
*/
private static void CombinationsNoRepetition(Int32 k, Int32 iBegin, Int32 iEnd)
{
if (k == 0)
{
PrintSubSet();
return;
}
if (success == false)
{
for (Int32 i = iBegin; i <= iEnd; i++)
{
subSetIndexes[k - 1] = i;
++iBegin;
CombinationsNoRepetition(k - 1, iBegin, iEnd);
if (success == true)
break;
}
}
return;
}
private static void PrintSubSet()
{
Int32 currentSubsetSum = 0;
// accumulate sum of current subset
for (Int32 i = 0; i < subSetIndexes.Length; i++)
{
currentSubsetSum += set[subSetIndexes[i]];
if(currentSubsetSum > sum) { break; }
}
if(currentSubsetSum > sum) { return; }
// if wanted sum: print current subset elements
if (currentSubsetSum == sum)
{
++numberOfSubsetSums;
// results.Add("(");
for (Int32 i = 0; i < subSetIndexes.Length; i++)
{
results.Add((set[subSetIndexes[i]]).ToString());
ResultSet.Add(set[subSetIndexes[i]]);
if (i < subSetIndexes.Length - 1)
{
// results.Add(" ,");
}
}
// results.Add(")");
Int32[] ResultSetArr = ResultSet.ToArray();
decimal[] ResultSetArrD = Array.ConvertAll(ResultSetArr, element => (decimal)element);
ResultSetArrD = Array.ConvertAll(ResultSetArrD, element => element / 10000m);
// var message = string.Join(Environment.NewLine, ResultSetArrD);
// message = string.Format("{0:0.0000}", message);
int l = ResultSetArrD.Length;
string[] ResultString = new string[l];
foreach(int i in ResultSetArrD)
{ResultString = Array.ConvertAll(ResultSetArrD, element => element.ToString("0.0000"));}
var message = string.Join(Environment.NewLine, ResultString);
decimal ResultSum = ResultSetArrD.Sum();
MessageBox.Show(message + "\n= " + ResultSum.ToString("0.0000"), "Result");
Array.Clear(ResultSetArrD, 0, ResultSetArrD.Length);
Array.Clear(ResultSetArr, 0, ResultSetArr.Length);
ResultSet.Clear();
message = null;
success = true;
foreach (Window window in Application.Current.Windows)
{
if (window.GetType() == typeof(MetTracker.GaugeCalc))
{
(window as MetTracker.GaugeCalc).CalculateBtn.Content = "Calculate";
}
}
return;
}
if (success == true)
return;
}
I added some limiting to reduce the amount of time before it reports a failure to find a combo. I also convert the array to a double to get around the headache the decimals were causing me. Works great!

How to get all unique posiblity's out of a list?

For my problem I have a list of a count larger then 6+. From that list I would like to make a list containing every possible combination of the original cards that is exactly 6 cards long. (they have to be unique and order doesn't matter)
so object
01,02,03,04,05,06
is the same for me as
06,05,04,03,02,01
//STARTER list with more then 6 value's
List < ClassicCard > lowCardsToRemove = FrenchTarotUtil.checkCountLowCardForDiscardChien(handCards);
The solution i found and used:
public static List generateAllSubsetCombinations(object[] fullSet, ulong subsetSize) {
if (fullSet == null) {
throw new ArgumentException("Value cannot be null.", "fullSet");
}
else if (subsetSize < 1) {
throw new ArgumentException("Subset size must be 1 or greater.", "subsetSize");
}
else if ((ulong)fullSet.LongLength < subsetSize) {
throw new ArgumentException("Subset size cannot be greater than the total number of entries in the full set.", "subsetSize");
}
// All possible subsets will be stored here
List<object[]> allSubsets = new List<object[]>();
// Initialize current pick; will always be the leftmost consecutive x where x is subset size
ulong[] currentPick = new ulong[subsetSize];
for (ulong i = 0; i < subsetSize; i++) {
currentPick[i] = i;
}
while (true) {
// Add this subset's values to list of all subsets based on current pick
object[] subset = new object[subsetSize];
for (ulong i = 0; i < subsetSize; i++) {
subset[i] = fullSet[currentPick[i]];
}
allSubsets.Add(subset);
if (currentPick[0] + subsetSize >= (ulong)fullSet.LongLength) {
// Last pick must have been the final 3; end of subset generation
break;
}
// Update current pick for next subset
ulong shiftAfter = (ulong)currentPick.LongLength - 1;
bool loop;
do {
loop = false;
// Move current picker right
currentPick[shiftAfter]++;
// If we've gotten to the end of the full set, move left one picker
if (currentPick[shiftAfter] > (ulong)fullSet.LongLength - (subsetSize - shiftAfter)) {
if (shiftAfter > 0) {
shiftAfter--;
loop = true;
}
}
else {
// Update pickers to be consecutive
for (ulong i = shiftAfter+1; i < (ulong)currentPick.LongLength; i++) {
currentPick[i] = currentPick[i-1] + 1;
}
}
} while (loop);
}
return allSubsets;
}
This one is not from me, but it does the job!
List <ClassicCard> lowCardsToRemove = FrenchTarotUtil.checkCountLowCardForDiscardChien(handCards);
var result = Combinator.Combinations(lowCardsToRemove, 6);
public static class Combinator
{
public static IEnumerable<IEnumerable<T>> Combinations<T>(this IEnumerable<T> elements, int k)
{
return k == 0 ? new[] { new T[0] } :
elements.SelectMany((e, i) =>
elements.Skip(i + 1).Combinations(k - 1).Select(c => (new[] { e }).Concat(c)));
}
}

Program to find minimum number in string

I have a c# class like so
internal class QueuedMinimumNumberFinder : ConcurrentQueue<int>
{
private readonly string _minString;
public QueuedMinimumNumberFinder(string number, int takeOutAmount)
{
if (number.Length < takeOutAmount)
{
throw new Exception("Error *");
}
var queueIndex = 0;
var queueAmount = number.Length - takeOutAmount;
var numQueue = new ConcurrentQueue<int>(number.ToCharArray().Where(m => (int) Char.GetNumericValue(m) != 0).Select(m=>(int)Char.GetNumericValue(m)).OrderBy(m=>m));
var zeroes = number.Length - numQueue.Count;
while (queueIndex < queueAmount)
{
int next;
if (queueIndex == 0)
{
numQueue.TryDequeue(out next);
Enqueue(next);
} else
{
if (zeroes > 0)
{
Enqueue(0);
zeroes--;
} else
{
numQueue.TryDequeue(out next);
Enqueue(next);
}
}
queueIndex++;
}
var builder = new StringBuilder();
while (Count > 0)
{
int next = 0;
TryDequeue(out next);
builder.Append(next.ToString());
}
_minString = builder.ToString();
}
public override string ToString() { return _minString; }
}
The point of the program is to find the minimum possible integer that can be made by taking out any x amount of characters from a string(example 100023 is string, if you take out any 3 letters, the minimum int created would be 100). My question is, is this the correct way to do this? Is there a better data structure that can be used for this problem?
First Edit:
Here's how it looks now
internal class QueuedMinimumNumberFinder
{
private readonly string _minString;
public QueuedMinimumNumberFinder(string number, int takeOutAmount)
{
var queue = new Queue<int>();
if (number.Length < takeOutAmount)
{
throw new Exception("Error *");
}
var queueIndex = 0;
var queueAmount = number.Length - takeOutAmount;
var numQueue = new List<int>(number.Where(m=>(int)Char.GetNumericValue(m)!=0).Select(m=>(int)Char.GetNumericValue(m))).ToList();
var zeroes = number.Length - numQueue.Count;
while (queueIndex < queueAmount)
{
if (queueIndex == 0)
{
var nextMin = numQueue.Min();
numQueue.Remove(nextMin);
queue.Enqueue(nextMin);
} else
{
if (zeroes > 1)
{
queue.Enqueue(0);
zeroes--;
} else
{
var nextMin = numQueue.Min();
numQueue.Remove(nextMin);
queue.Enqueue(nextMin);
}
}
queueIndex++;
}
var builder = new StringBuilder();
while (queue.Count > 0)
{
builder.Append(queue.Dequeue().ToString());
}
_minString = builder.ToString();
}
public override string ToString() { return _minString; }
}
A pretty simple and efficient implementation can be made, once you realize that your input string digits map to the domain of only 10 possible values: '0' .. '9'.
This can be encoded as the number of occurrences of a specific digit in your input string using a simple array of 10 integers: var digit_count = new int[10];
#MasterGillBates describes this idea in his answer.
You can then regard this array as your priority queue from which you can dequeue the characters you need by iteratively removing the lowest available character (decreasing its occurrence count in the array).
The code sample below provides an example implementation for this idea.
public static class MinNumberSolver
{
public static string GetMinString(string number, int takeOutAmount)
{
// "Add" the string by simply counting digit occurrance frequency.
var digit_count = new int[10];
foreach (var c in number)
if (char.IsDigit(c))
digit_count[c - '0']++;
// Now remove them one by one in lowest to highest order.
// For the first character we skip any potential leading 0s
var selected = new char[takeOutAmount];
var start_index = 1;
selected[0] = TakeLowest(digit_count, ref start_index);
// For the rest we start in digit order at '0' first.
start_index = 0;
for (var i = 0; i < takeOutAmount - 1; i++)
selected[1 + i] = TakeLowest(digit_count, ref start_index);
// And return the result.
return new string(selected);
}
private static char TakeLowest(int[] digit_count, ref int start_index)
{
for (var i = start_index; i < digit_count.Length; i++)
{
if (digit_count[i] > 0)
{
start_index = ((--digit_count[i] > 0) ? i : i + 1);
return (char)('0' + i);
}
}
throw new InvalidDataException("Input string does not have sufficient digits");
}
}
Just keep a count of how many times each digit appears. An array of size 10 will do. Count[i] gives the count of digit i.
Then pick the smallest non-zero i first, then pick the smallest etc and form your number.
Here's my solution using LINQ:
public string MinimumNumberFinder(string number, int takeOutAmount)
{
var ordered = number.OrderBy(n => n);
var nonZero = ordered.SkipWhile(n => n == '0');
var zero = ordered.TakeWhile(n => n == '0');
var result = nonZero.Take(1)
.Concat(zero)
.Concat(nonZero.Skip(1))
.Take(number.Length - takeOutAmount);
return new string(result.ToArray());
}
You could place every integer into a list and find all possible sequences of these values. From the list of sequences, you could sort through taking only the sets which have the number of integers you want. From there, you can write a quick function which parses a sequence into an integer. Next, you could store all of your parsed sequences into an array or an other data structure and sort based on value, which will allow you to select the minimum number from the data structure. There may be simpler ways to do this, but this will definitely work and gives you options as far as how many digits you want your number to have.
If I'm understanding this correctly, why don't you just pick out your numbers starting with the smallest number greater than zero. Then pick out all zeroes, then any remaining number if all the zeroes are picked up. This is all depending on the length of your ending result
In your example you have a 6 digit number and you want to pick out 3 digits. This means you'll only have 3 digits left. If it was a 10 digit number, then you would end up with a 7 digit number, etc...
So have an algorithm that knows the length of your starting number, how many digits you plan on removing, and the length of your ending number. Then just pick out the numbers.
This is just quick and dirty code:
string startingNumber = "9999903040404"; // "100023";
int numberOfCharactersToRemove = 3;
string endingNumber = string.Empty;
int endingNumberLength = startingNumber.Length - numberOfCharactersToRemove;
while (endingNumber.Length < endingNumberLength)
{
if (string.IsNullOrEmpty(endingNumber))
{
// Find the smallest digit in the starting number
for (int i = 1; i <= 9; i++)
{
if (startingNumber.Contains(i.ToString()))
{
endingNumber += i.ToString();
startingNumber = startingNumber.Remove(startingNumber.IndexOf(i.ToString()), 1);
break;
}
}
}
else if (startingNumber.Contains("0"))
{
// Add any zeroes
endingNumber += "0";
startingNumber = startingNumber.Remove(startingNumber.IndexOf("0"), 1);
}
else
{
// Add any remaining numbers from least to greatest
for (int i = 1; i <= 9; i++)
{
if (startingNumber.Contains(i.ToString()))
{
endingNumber += i.ToString();
startingNumber = startingNumber.Remove(startingNumber.IndexOf(i.ToString()), 1);
break;
}
}
}
}
Console.WriteLine(endingNumber);
100023 starting number resulted in 100 being the end result
9999903040404 starting number resulted in 3000044499 being the end result
Here's my version to fix this problem:
DESIGN:
You can sort your list using a binary tree , there are a lot of
implementations , I picked this one
Then you can keep track of the number of the Zeros you have in your
string Finally you will end up with two lists: I named one
SortedDigitsList and the other one ZeroDigitsList
perform a switch case to determine which last 3 digits should be
returned
Here's the complete code:
class MainProgram2
{
static void Main()
{
Tree theTree = new Tree();
Console.WriteLine("Please Enter the string you want to process:");
string input = Console.ReadLine();
foreach (char c in input)
{
// Check if it's a digit or not
if (c >= '0' && c <= '9')
{
theTree.Insert((int)Char.GetNumericValue(c));
}
}
//End of for each (char c in input)
Console.WriteLine("Inorder traversal resulting Tree Sort without the zeros");
theTree.Inorder(theTree.ReturnRoot());
Console.WriteLine(" ");
//Format the output depending on how many zeros you have
Console.WriteLine("The final 3 digits are");
switch (theTree.ZeroDigitsList.Count)
{
case 0:
{
Console.WriteLine("{0}{1}{2}", theTree.SortedDigitsList[0], theTree.SortedDigitsList[1], theTree.SortedDigitsList[2]);
break;
}
case 1:
{
Console.WriteLine("{0}{1}{2}", theTree.SortedDigitsList[0], 0, theTree.SortedDigitsList[2]);
break;
}
default:
{
Console.WriteLine("{0}{1}{2}", theTree.SortedDigitsList[0], 0, 0);
break;
}
}
Console.ReadLine();
}
}//End of main()
}
class Node
{
public int item;
public Node leftChild;
public Node rightChild;
public void displayNode()
{
Console.Write("[");
Console.Write(item);
Console.Write("]");
}
}
class Tree
{
public List<int> SortedDigitsList { get; set; }
public List<int> ZeroDigitsList { get; set; }
public Node root;
public Tree()
{
root = null;
SortedDigitsList = new List<int>();
ZeroDigitsList = new List<int>();
}
public Node ReturnRoot()
{
return root;
}
public void Insert(int id)
{
Node newNode = new Node();
newNode.item = id;
if (root == null)
root = newNode;
else
{
Node current = root;
Node parent;
while (true)
{
parent = current;
if (id < current.item)
{
current = current.leftChild;
if (current == null)
{
parent.leftChild = newNode;
return;
}
}
else
{
current = current.rightChild;
if (current == null)
{
parent.rightChild = newNode;
return;
}
}
}
}
}
//public void Preorder(Node Root)
//{
// if (Root != null)
// {
// Console.Write(Root.item + " ");
// Preorder(Root.leftChild);
// Preorder(Root.rightChild);
// }
//}
public void Inorder(Node Root)
{
if (Root != null)
{
Inorder(Root.leftChild);
if (Root.item > 0)
{
SortedDigitsList.Add(Root.item);
Console.Write(Root.item + " ");
}
else
{
ZeroDigitsList.Add(Root.item);
}
Inorder(Root.rightChild);
}
}

(Dynamic programming) How to maximize room utilization with a list of meeting?

I am trying this problem using dynamic programming
Problem:
Given a meeting room and a list of intervals (represent the meeting), for e.g.:
interval 1: 1.00-2.00
interval 2: 2.00-4.00
interval 3: 14.00-16.00
...
etc.
Question:
How to schedule the meeting to maximize the room utilization, and NO meeting should overlap with each other?
Attempted solution
Below is my initial attempt in C# (knowing it is a modified Knapsack problem with constraints). However I had difficulty in getting the result correctly.
bool ContainsOverlapped(List<Interval> list)
{
var sortedList = list.OrderBy(x => x.Start).ToList();
for (int i = 0; i < sortedList.Count; i++)
{
for (int j = i + 1; j < sortedList.Count; j++)
{
if (sortedList[i].IsOverlap(sortedList[j]))
return true;
}
}
return false;
}
public bool Optimize(List<Interval> intervals, int limit, List<Interval> itemSoFar){
if (intervals == null || intervals.Count == 0)
return true; //no more choice
if (Sum(itemSoFar) > limit) //over limit
return false;
var arrInterval = intervals.ToArray();
//try all choices
for (int i = 0; i < arrInterval.Length; i++){
List<Interval> remaining = new List<Interval>();
for (int j = i + 1; j < arrInterval.Length; j++) {
remaining.Add(arrInterval[j]);
}
var partialChoice = new List<Interval>();
partialChoice.AddRange(itemSoFar);
partialChoice.Add(arrInterval[i]);
//should not schedule overlap
if (ContainsOverlapped(partialChoice))
partialChoice.Remove(arrInterval[i]);
if (Optimize(remaining, limit, partialChoice))
return true;
else
partialChoice.Remove(arrInterval[i]); //undo
}
//try all solution
return false;
}
public class Interval
{
public bool IsOverlap(Interval other)
{
return (other.Start < this.Start && this.Start < other.End) || //other < this
(this.Start < other.Start && other.End < this.End) || // this covers other
(other.Start < this.Start && this.End < other.End) || // other covers this
(this.Start < other.Start && other.Start < this.End); //this < other
}
public override bool Equals(object obj){
var i = (Interval)obj;
return base.Equals(obj) && i.Start == this.Start && i.End == this.End;
}
public int Start { get; set; }
public int End { get; set; }
public Interval(int start, int end){
Start = start;
End = end;
}
public int Duration{
get{
return End - Start;
}
}
}
Edit 1
Room utilization = amount of time the room is occupied. Sorry for confusion.
Edit 2
for simplicity: the duration of each interval is integer, and the start/end time start at whole hour (1,2,3..24)
I'm not sure how you are relating this to a knapsack problem. To me it seems more of a vertex cover problem.
First sort the intervals as per their start times and form a graph representation in the form of adjacency matrix or list.
The vertices shall be the interval numbers. There shall be an edge between two vertices if the corresponding intervals overlap with each other. Also, each vertex shall be associated with a value equal to the interval's duration.
The problem then becomes choosing the independent vertices in such a way that the total value is maximum.
This can be done through dynamic programming. The recurrence relation for each vertex shall be as follows:
V[i] = max{ V[j] | j < i and i->j is an edge,
V[k] + value[i] | k < i and there is no edge between i and k }
Base Case V[1] = value[1]
Note:
The vertices should be numbered in increasing order of their start times. Then if there are three vertices:
i < j < k, and if there is no edge between vertex i and vertex j, then there cannot be any edge between vertex i and vertex k.
Good approach is to create class that can easily handle for you.
First I create helper class for easily storing intervals
public class FromToDateTime
{
private DateTime _start;
public DateTime Start
{
get
{
return _start;
}
set
{
_start = value;
}
}
private DateTime _end;
public DateTime End
{
get
{
return _end;
}
set
{
_end = value;
}
}
public FromToDateTime(DateTime start, DateTime end)
{
Start = start;
End = end;
}
}
And then here is class Room, where all intervals are and which has method "addInterval", which returns true, if interval is ok and was added and false, if it does not.
btw : I got a checking condition for overlapping here : Algorithm to detect overlapping periods
public class Room
{
private List<FromToDateTime> _intervals;
public List<FromToDateTime> Intervals
{
get
{
return _intervals;
}
set
{
_intervals = value;
}
}
public Room()
{
Intervals = new List<FromToDateTime>();
}
public bool addInterval(FromToDateTime newInterval)
{
foreach (FromToDateTime interval in Intervals)
{
if (newInterval.Start < interval.End && interval.Start < newInterval.End)
{
return false;
}
}
Intervals.Add(newInterval);
return true;
}
}
While the more general problem (if you have multiple number of meeting rooms) is indeed NP-Hard, and is known as the interval scheduling problem.
Optimal solution for 1-d problem with one classroom:
For the 1-d problem, choosing the (still valid) earliest deadline first solves the problem optimally.
Proof: by induction, the base clause is the void clause - the algorithm optimally solves a problem with zero meetings.
The induction hypothesis is the algorithm solves the problem optimally for any number of k tasks.
The step: Given a problem with n meetings, hose the earliest deadline, and remove all invalid meetings after choosing it. Let the chosen earliest deadline task be T.
You will get a new problem of smaller size, and by invoking the algorithm on the reminder, you will get the optimal solution for them (induction hypothesis).
Now, note that given that optimal solution, you can add at most one of the discarded tasks, since you can either add T, or another discarded task - but all of them overlaps T - otherwise they wouldn't have been discarded), thus, you can add at most one from all discarded tasks, same as the suggested algorithm.
Conclusion: For 1 meeting room, this algorithm is optimal.
QED
high level pseudo code of the solution:
findOptimal(list<tasks>):
res = [] //empty list
sort(list) //according to deadline/meeting end
while (list.IsEmpty() == false):
res = res.append(list.first())
end = list.first().endTime()
//remove all overlaps with the chosen meeting
while (list.first().startTine() < end):
list.removeFirst()
return res
Clarification: This answer assumes "Room Utilization" means maximize number of meetings placed in the room.
Thanks all, here is my solution based on this Princeton note on dynamic programming.
Algorithm:
Sort all events by end time.
For each event, find p[n] - the latest event (by end time) which does not overlap with it.
Compute the optimization values: choose the best between including/not including the event.
Optimize(n) {
opt(0) = 0;
for j = 1 to n-th {
opt(j) = max(length(j) + opt[p(j)], opt[j-1]);
}
}
The complete source-code:
namespace CommonProblems.Algorithm.DynamicProgramming {
public class Scheduler {
#region init & test
public List<Event> _events { get; set; }
public List<Event> Init() {
if (_events == null) {
_events = new List<Event>();
_events.Add(new Event(8, 11));
_events.Add(new Event(6, 10));
_events.Add(new Event(5, 9));
_events.Add(new Event(3, 8));
_events.Add(new Event(4, 7));
_events.Add(new Event(0, 6));
_events.Add(new Event(3, 5));
_events.Add(new Event(1, 4));
}
return _events;
}
public void DemoOptimize() {
this.Init();
this.DynamicOptimize(this._events);
}
#endregion
#region Dynamic Programming
public void DynamicOptimize(List<Event> events) {
events.Add(new Event(0, 0));
events = events.SortByEndTime();
int[] eventIndexes = getCompatibleEvent(events);
int[] utilization = getBestUtilization(events, eventIndexes);
List<Event> schedule = getOptimizeSchedule(events, events.Count - 1, utilization, eventIndexes);
foreach (var e in schedule) {
Console.WriteLine("Event: [{0}- {1}]", e.Start, e.End);
}
}
/*
Algo to get optimization value:
1) Sort all events by end time, give each of the an index.
2) For each event, find p[n] - the latest event (by end time) which does not overlap with it.
3) Compute the optimization values: choose the best between including/not including the event.
Optimize(n) {
opt(0) = 0;
for j = 1 to n-th {
opt(j) = max(length(j) + opt[p(j)], opt[j-1]);
}
display opt();
}
*/
int[] getBestUtilization(List<Event> sortedEvents, int[] compatibleEvents) {
int[] optimal = new int[sortedEvents.Count];
int n = optimal.Length;
optimal[0] = 0;
for (int j = 1; j < n; j++) {
var thisEvent = sortedEvents[j];
//pick between 2 choices:
optimal[j] = Math.Max(thisEvent.Duration + optimal[compatibleEvents[j]], //Include this event
optimal[j - 1]); //Not include
}
return optimal;
}
/*
Show the optimized events:
sortedEvents: events sorted by end time.
index: event index to start with.
optimal: optimal[n] = the optimized schedule at n-th event.
compatibleEvents: compatibleEvents[n] = the latest event before n-th
*/
List<Event> getOptimizeSchedule(List<Event> sortedEvents, int index, int[] optimal, int[] compatibleEvents) {
List<Event> output = new List<Event>();
if (index == 0) {
//base case: no more event
return output;
}
//it's better to choose this event
else if (sortedEvents[index].Duration + optimal[compatibleEvents[index]] >= optimal[index]) {
output.Add(sortedEvents[index]);
//recursive go back
output.AddRange(getOptimizeSchedule(sortedEvents, compatibleEvents[index], optimal, compatibleEvents));
return output;
}
//it's better NOT choose this event
else {
output.AddRange(getOptimizeSchedule(sortedEvents, index - 1, optimal, compatibleEvents));
return output;
}
}
//compatibleEvents[n] = the latest event which do not overlap with n-th.
int[] getCompatibleEvent(List<Event> sortedEvents) {
int[] compatibleEvents = new int[sortedEvents.Count];
for (int i = 0; i < sortedEvents.Count; i++) {
for (int j = 0; j <= i; j++) {
if (!sortedEvents[j].IsOverlap(sortedEvents[i])) {
compatibleEvents[i] = j;
}
}
}
return compatibleEvents;
}
#endregion
}
public class Event {
public int EventId { get; set; }
public bool IsOverlap(Event other) {
return !(this.End <= other.Start ||
this.Start >= other.End);
}
public override bool Equals(object obj) {
var i = (Event)obj;
return base.Equals(obj) && i.Start == this.Start && i.End == this.End;
}
public int Start { get; set; }
public int End { get; set; }
public Event(int start, int end) {
Start = start;
End = end;
}
public int Duration {
get {
return End - Start;
}
}
}
public static class ListExtension {
public static bool ContainsOverlapped(this List<Event> list) {
var sortedList = list.OrderBy(x => x.Start).ToList();
for (int i = 0; i < sortedList.Count; i++) {
for (int j = i + 1; j < sortedList.Count; j++) {
if (sortedList[i].IsOverlap(sortedList[j]))
return true;
}
}
return false;
}
public static List<Event> SortByEndTime(this List<Event> events) {
if (events == null) return new List<Event>();
return events.OrderBy(x => x.End).ToList();
}
}
}

Why Class instance overwrites another instance

I've an issue to ask you guys.
I have a class shown below:
public class Node
{
public int Kova1; // Kova 1
public int Kova2; // Kova 2
public int Kova3; // Kova 3
public int ActionNo; // Yapılan İşlem
public Node(int kova1, int kova2, int kova3, int actionNumber)
{
Kova1 = kova1;
Kova2 = kova2;
Kova3 = kova3;
ActionNo = actionNumber;
}
public Node(int kova1, int kova2, int kova3)
{
Kova1 = kova1;
Kova2 = kova2;
Kova3 = kova3;
}
public Node()
{
}
public Node AnneNode;
}
And these functions:
public void CocukNodeOlustur(LinkedList<Node> Acik, LinkedList<Node> Kapali, Node temp)
{
Node cocukState;
Node temp2 = temp;
for (int i = 0; i < 12; i++)
{
cocukState = YeniStateOlustur(temp, i);
if ((ActionKontrol(cocukState)) && (GoalBulundu(Acik, Kapali, cocukState)) &&
((cocukState.Kova1 != temp2.Kova1) && (cocukState.Kova2 != temp2.Kova2) && (cocukState.Kova3 != temp2.Kova3)))
{
cocukState.AnneNode = temp;
Acik.AddFirst(temp);
}
}
}
public Node YeniStateOlustur(Node s, int j)
{
int tempKova1, tempKova2, tempKova3;
Node yeniCocuk = new Node();
yeniCocuk = s;
yeniCocuk.ActionNo = j;
// Gelen numaraya göre uygulanan işlemin seçimi yapılıyor.
switch (j)
{
case 0:
{
yeniCocuk.Kova1 += (3 - yeniCocuk.Kova1);
yeniCocuk.Kova2 += 0;
yeniCocuk.Kova3 += 0;
}
break;
case 1:
{
yeniCocuk.Kova1 += 0;
yeniCocuk.Kova2 += (5 - yeniCocuk.Kova2);
yeniCocuk.Kova3 += 0;
}
break;
}
return yeniCocuk;
}
In the main function
Node temp = new Node();
while (!(Acik.Count == 0))
{
p.CocukNodeOlustur(Acik, Kapali, temp);
Kapali.AddLast(temp);
}
So When I debug my program, I see that Whenever the code jumps to the YeniStateOlustur() function, all the Node instance's in program is affected by the changes in YeniStateOlustur(). It seems the instance in the function overwrite all instances of Node class.
I don't understand why it happens?
How can I overcome this?
My best regards and sory for the long post.
The problem is that all of the nodes are the same instance. Your sample code includes "new Node()" only twice, and in the second case (inside the method YeniStateOlustur), the new instance is immediately discarded. That function therefore returns the same node that was passed to it:
public Node YeniStateOlustur(Node s, int j)
{
int tempKova1, tempKova2, tempKova3;
Node yeniCocuk = new Node();
yeniCocuk = s;
//...
return yeniCocuk;
}
In the method CocukNodeOlustur, all node variables point to the same Node:
public void CocukNodeOlustur(LinkedList<Node> Acik, LinkedList<Node> Kapali, Node temp)
{
// here, temp == temp
Node cocukState;
// now, temp == temp and cocukState is uninitialized.
Node temp2 = temp;
// now, temp == temp, temp2 == temp, and cocukState is uninitialized.
for (int i = 0; i < 12; i++)
{
cocukState = YeniStateOlustur(temp, i);
// now, temp == temp, temp2 == temp, and cocukState == temp
if ((ActionKontrol(cocukState)) && (GoalBulundu(Acik, Kapali, cocukState)) &&
((cocukState.Kova1 != temp2.Kova1) && (cocukState.Kova2 != temp2.Kova2) && (cocukState.Kova3 != temp2.Kova3)))
{
cocukState.AnneNode = temp;
Acik.AddFirst(temp);
}
}
}
Your code seems to assume that Node is a value type (struct), but it is obviously a reference type (class). If you're unsure about the difference, you should take a step back and do some reading and experimentation.
A quick fix might be to change the declaration of Node to a struct, but I would recommend against that. Programming with structs can be very tricky, and that would be especially true if your understanding of the differences between structs and classes is shaky.

Categories