I am trying to repair graphs by deleting one edges. The only problem I am running in to is, when there are multiple cycles in the graph for example: 0 3, 2 3, 0 2, 1 2, 3 1. This can be fixed by extracting 3 1, but how do I let the program no that 3 1 is the edge that has to be removed?
Any suggestions? :)
Formatted code from comment...
...
else if (backedges.Count > 1)
{
foreach (Side side in backedges)
{
Node end = Side.node2;
Node begin = Side.node1;
List<Side> allsidesycle = new List<Side>();
while (begin != Side.node2)
{
end = begin;
begin = begin.pi;
Side be = new Side(begin, end);
allsidescycle.Add(be);
}
To find cycles you may want to use breadth first search (bfs).
Using bfs on unweighted (or equally weighted) graph grantees that then the first time a node is visited is the shortest path to that node.
If you visit it for the second time - you have a cycle. To remove it modify the graph by deleting that 2nd edge.
Related
While doing a code Kata, I've run into a slight logical problem that I can't figure out a solution to. It isn't a hard-and-fast requirement of completing the task but it has me intrigued as to how it could be handled.
The Kata is simulating applying pricing discounts and a supermarket checkout (see full Kata here) through a collection of pricing rules. To play around with some inheritance and interface capabilities, I've added a "Buy X, get Y free" rule. It works fine when the Y in question is 1, but starts getting a little hazy after that...
For example, I experimented with the idea of "Buy 3, get 2 free". I tried doing this by grouping the items in groups of 5, and working out the discount of each group by subtracting the price of two of the items:
public override double CalculateDiscount(Item[] items)
{
//per the example described above
//_groupSize = 5, _buy = 3
//meaning 2 out of every group of 5 items should be free
var discountGroups = new List<IEnumerable<Item>>();
for (var i = 0; i < items.Length / _groupSize; i++)
{
discountGroups.Add(items.Skip(i * _groupSize).Take(_groupSize));
}
return discountGroups
.Sum(group => group
.Skip(_buy)
.Sum(item => item.Price)
);
}
What I found is that the above code works as expected (if each item has a Price property of 1.00, the above would return 2.00). An edge case that I am looking to solve is that it doesn't take affect until the fifth item is added (so the price as you ad each item would go 1.00, 2.00, 3.00, 4.00, 3.00).
What I would ideally like is that, once you have three items in your collection, the next two items are free, whether you choose to take just one or two of them shouldn't affect the price. I understand this isn't hugely realistic to the domain, but I was interested in trying to solve it as a technical problem.
I've had a few cracks at it but haven't successfully gotten any closer than the above code. I figure that what I need to do is group the array into the minimum number of bought items required, then a variable number of free items. I could probably hard-code something to solve the issue once, but this gets complicated if I were to simulate buying 3 items and getting 2 free, then buying 3 items but only taking one free one.
Any advice on how to go about this would be really appreciated!
Thanks,
Mark
Your discount-calculation has some bugs, for example you dont create groups if the item-count is less than groupSize. So change i < to i <=:
for (var i = 0; i <= items.Length / groupSize; i++)
{
discountGroups.Add(items.Skip(i * groupSize).Take(groupSize));
}
Maybe that's already all.
I would just like to add that the extension method .Chunk() was added to the System.Linq namespace in .NET 6, and it does exactly what you are doing to create discountGroups; it splits the source collection into an IEnumerable of chunks of the requested chunk size:
source: { 1, 2, 3, 4, 5, 6, 7, 8 }
var chunks = source.Chunk(3);
chunks: { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8 } }
If the item count in the source enumerable is not exactly divisible by the wanted chunk size, the last chunk will simply consist of the remaining items (i.e. the last chunk may be smaller in size than the other chunks).
By using .Chunk(), you could therefore replace this:
var discountGroups = new List<IEnumerable<Item>>();
for (...)
{
discountGroups.Add(items.Skip(i * _groupSize).Take(_groupSize));
}
with this:
var discountGroups = items.Chunk(_groupSize).ToList();
I have a 2D grid in my game made up of nodes. I have enemies which follow players using the A* pathfinding algorithm (using the diagonal distance heuristic for H as diagonal movement is allowed).
The pathfinding works nearly all of the time however, when a player and an enemy are on exactly opposite (diagonally, vertically, or horizontally) sides of a wall, the enemy becomes stuck and stops moving.
From the below screenshot you can see the path found in this scenario, for some reason, a node in the opposite direction of the path is also being added to the path:
Below is my code for my F, G and H calculations (in my node class):
// Calculates distance cost from current node to an adjacent node.
public void CalculateG(Node nodeTarget)
{
// If the node is diagonal to the current node, its cost of movement is higher.
if (TileX != nodeTarget.TileX && TileY != nodeTarget.TileY)
{
intG = 14;
}
else intG = 10;
}
// Calculates H cost using the diagonal shortcut method.
public void CalculateH(Node nodeTarget)
{
int intXDiff = Math.Abs(TileX - nodeTarget.TileX);
int intYDiff = Math.Abs(TileY - nodeTarget.TileY);
if (intXDiff > intYDiff)
intH = 14 * intYDiff + 10 * (intXDiff - intYDiff);
else intH = 14 * intXDiff + 10 * (intYDiff - intXDiff);
}
public void CalculateF()
{
intF = intG + intH; // F = G + H
}
The code for my pathfinding class is shown below:
public class Path
{
private List<Node> PathOfNodes; // Stores the path of nodes to follow to the destination.
public List<Node> NodePath
{
get { return PathOfNodes; }
}
// Constructor takes the starting node, destination and the grid to generate the path.
public Path(Node Start, Node Destination, GridLayer grid)
{
List<Node> openNodes = new List<Node>(); // Creates a list of possible nodes for the path.
List<Node> closedNodes = new List<Node>(); // Creates a list of nodes confirmed for the path.
openNodes.Add(Start); // Step 1: Adds the current node to the possibilities list.
// Loops while the destination is not on the closed list and while the open nodes list is not empty.
while (!closedNodes.Contains(Destination) && openNodes.Any())
{
// Sorts the open list according to f scores.
openNodes.Sort((node, otherNode) => node.F.CompareTo(otherNode.F));
Node nodeCurrent = openNodes[0]; // The node with the lowest F score is set as the current node.
openNodes.Remove(nodeCurrent);
closedNodes.Add(nodeCurrent); // The current node is moved to the closed list.
// Creates a list containing all the nodes adjacent to the current node.
List<Node> adjacentNodes = AddAdjacentNodes(grid, nodeCurrent);
CheckAdjacentNodes(adjacentNodes, ref closedNodes, ref openNodes, nodeCurrent, Destination);
}
EstablishPath(closedNodes);
}
// Adds all the adjacent nodes from above the current node turning clockwise.
public List<Node> AddAdjacentNodes(GridLayer grid, Node nodeCurrent)
{
int intCol = nodeCurrent.TileX / nodeCurrent.TileWidth;
int intRow = nodeCurrent.TileY / nodeCurrent.TileHeight; // Gets the current node's indices.
List<Node> adjacentNodes = new List<Node>(); // Stores the nodes adjacent to the current node.
// The if statements check whether the node is within the grid before adding the node.
if (intRow - 1 >= 0)
adjacentNodes.Add(grid.Nodes[intCol, intRow - 1]); // Above
if ((intCol + 1 < 21 && intRow - 1 >= 0) && (grid.Nodes[intCol + 1, intRow].Traversable) && (grid.Nodes[intCol, intRow - 1].Traversable))
adjacentNodes.Add(grid.Nodes[intCol + 1, intRow - 1]); // Diagonally Right Up
if (intCol + 1 < 21)
adjacentNodes.Add(grid.Nodes[intCol + 1, intRow]); // Right
if (intCol + 1 < 21 && intRow + 1 < 12 && (grid.Nodes[intCol + 1, intRow].Traversable) && (grid.Nodes[intCol, intRow + 1].Traversable))
adjacentNodes.Add(grid.Nodes[intCol + 1, intRow + 1]); // Diagonally Right Down
if (intRow + 1 < 12)
adjacentNodes.Add(grid.Nodes[intCol, intRow + 1]); // Below
if (intCol - 1 >= 0 && intRow + 1 < 12 && (grid.Nodes[intCol - 1, intRow].Traversable) && (grid.Nodes[intCol, intRow + 1].Traversable))
adjacentNodes.Add(grid.Nodes[intCol - 1, intRow + 1]); // Diagonally Left Down
if (intCol - 1 >= 0)
adjacentNodes.Add(grid.Nodes[intCol - 1, intRow]); // Left
if (intCol - 1 >= 0 && intRow - 1 >= 0 && (grid.Nodes[intCol - 1, intRow].Traversable) && (grid.Nodes[intCol, intRow - 1].Traversable))
adjacentNodes.Add(grid.Nodes[intCol - 1, intRow - 1]); // Diagonally Left Up
return adjacentNodes;
}
// Checks the adjacent node list for nodes to be added to the open list/closed list.
private void CheckAdjacentNodes(List<Node> adjacentNodes, ref List<Node> closedNodes, ref List<Node> openNodes, Node nodeCurrent, Node destinationNode)
{
foreach (Node node in adjacentNodes)
{ // Checks each node to see if it is traversable and not already on the closed list.
if (node.Traversable && !closedNodes.Contains(node))
{
// If the node is not on the open list, add it, set its parent as the current node and calculate its F, G, and H values.
if (!openNodes.Contains(node))
{
openNodes.Add(node);
node.Parent = nodeCurrent;
node.CalculateG(nodeCurrent);
node.CalculateH(destinationNode);
node.CalculateF();
}
else // If the node was already on the open list...
{
// If its G cost of the node is lower than its parent + its own...
if (node.G < node.G + node.Parent.G)
{
// Make the node's parent the current node and recalculate its values.
node.Parent = nodeCurrent;
node.CalculateG(nodeCurrent.Parent);
node.CalculateF();
}
}
}
}
}
private void EstablishPath(List<Node> closedNodes)
{
PathOfNodes = new List<Node>(); // Stores the path for the entity to follow to its target.
for (int intNodeIndex = closedNodes.Count - 1; (intNodeIndex > 1); intNodeIndex--)
{
// Starting from the top of the closed list, add each node's parent to the path
// until the starting node is reached (index is 0).
PathOfNodes.Add(closedNodes[intNodeIndex].Parent);
}
PathOfNodes.Remove(null); // Remove the final null node (as the final node has no parent).
}
}
I believe there is a problem with the comparision between a node's G score and the G score of itself and its parent. I'm not sure if I am recalculating the G score using the correct adjacent node after the comparsion. If someone could make this clearer it would be really helpful. The article I followed was:
https://www.gamedev.net/resources/_/technical/artificial-intelligence/a-pathfinding-for-beginners-r2003
however, I don't think I have implemented this step into my code correctly:
If it is on the open list already, check to see if this path to that square is better, using G cost as the measure. A lower G cost means that this is a better path. If so, change the parent of the square to the current square, and recalculate the G and F scores of the square.
Please let me know of any additional information needed for this problem.
Thanks in advance.
Edit: I don't have any collision detection set up for enemies colliding with walls. The path is followed by the enemy moving towards the last node in the node path list.
Edit: My G calculation is wrong, the scores are not accumulated.
After correctly accumulating the G scores, it's now finding paths in all 4 directions (with the heuristic set to 0). I'm guessing this means that all the closed list nodes are being added to my final path meaning a problem in my establish path method.
The red numbers show the f score of the node, the blue numbers show the f score of the parent of the node (so you can tell which node is its parent).
After correctly accumulating the G scores, it's now finding paths in all 4 directions (with the heuristic set to 0).
Edit: I've fixed the problem. I'll submit an answer shortly but basically, my establish path method didn't do what it should. Instead of adding everything from the closed list, it was supposed to start at the end of the closed list follow through the chain of parents from the end until the starting node was added.
I do see some flaws in your code. This might not be the problem, but let's hope it is.
When you're checking if the node is better than other node in the openlist, you're doing something weird. That if-statement never even triggers, because something is never smaller than itself + a positive integer. Also you didn't even set the G-cost of the node yet. So therefore you can't check it either. This piece of code probably would result in a error (unless G has a standard value).
However I think this piece of code doesn't even get reached. Because I suspect that this piece of code allways triggers:
if (!openNodes.Contains(node))
You know why?
I can see the idea your trying to achieve, but there isn't another exact copy of the node in the openset. First of all because the nodes in the openset have their G, H and F cost set, and the node you're checking doesn't (so they're not the same). Thereby if the had the same data in them, I think it still wouldn't trigger because both nodes have another location in your computer (not 100% sure about this part). This also goes for checking if the node is in the closedset.
What you should be doing is check if there is a node in the openlist with the same location as the node you're checking. If the node is already in the list, than you should calculate the G-cost of the node we're dealing with. And check if the G-cost is smaller than the G-cost currently in the list, and change parent etc accordingly.
For the rest your code seems fine, although it's often hard to see mistakes in pathfinder. Hope this help, if you have any questions don't hesitate to ask.
First of all, thanks to J4stM4rt for identifying that I was making a useless comparison (integerA < integerA + positive integer) and Eric Lippert for suggesting that I should set the heuristic to 0 to identify the problem.
My first problem was that I was not accumulating the g-scores for the path. In my G score calculation method I needed to have intG = 10 (or 14) + targetNode.G.
The second problem was the problem mentioned by J4stM4rt in that I was checking if the node's g score was greater than itself + another node's g score which would always be true.
The final problem was in the establish path method, I was adding the parent of every node in the closed list to the path instead of starting at the end and adding each subsequent parent to the path until I reached the start. Below you can see the corrections to my code:
G-Score calculation:
// Calculates distance cost from start node to an adjacent node.
public void CalculateG(Node nodeTarget)
{ // The g-score is cumulative so the target node's score is also added.
// If the node is diagonal to the current node, its cost of movement is higher.
if (TileX != nodeTarget.TileX && TileY != nodeTarget.TileY)
{
intG = nodeTarget.G + 14;
}
else intG = nodeTarget.G + 10;
}
Establish path method:
private void EstablishPath(List<Node> closedNodes, Node nodeStart, Node nodeDestination)
{
PathOfNodes = new List<Node>(); // Stores the path for the entity to follow to its target.
// Start at the end of the path.
Node nodeToAdd = closedNodes[closedNodes.Count - 1];
while (!PathOfNodes.Contains(nodeStart))
{ // Add each node's parent until the start is reached.
PathOfNodes.Add(nodeToAdd);
nodeToAdd = nodeToAdd.Parent;
}
PathOfNodes.Remove(null); // Remove the final null node (as the final node had no parent).
}
G score comparison (this may still actually be wrong, I tried changing it to (node.G (cost of moving from the current node's parent to this node) < nodeCurrent.G (cost of moving from the current nodes parent to the current node) + calculation of g for moving from current node to this node) however, this resulted in my enemies becoming stuck again so I changed it to the following and it works seemingly ok:
if (node.G < nodeCurrent.G)
{
// Make the node's parent the current node's parent and recalculate its values.
node.Parent = nodeCurrent;
node.CalculateG(nodeCurrent);
node.CalculateF();
}
I want to ask how can I implement binary search in a List where I have 50,000 structures.
I sort this list by word like this listSub.OrderBy(s => s.word);
public struct SubItem
{
public string word;
public int count;
public SubItem(string word, int count)
{
this.word = word;
this.count = count;
}
}
I dont know how binary search in List<SubItem>. Can you help me?
The key to a binary search is that all of the items to the left of the center item are less than the center item, and to the right are all greater. The other key is that any given section of the list behaves as a sorted list in its own right, and thus that property still applies. So you keep breaking the list in half until you have found your element. This is usually done with recursion, with an empty list as the base case that the element does not exist in the list.
Here is some pseudocode to get you started:
find (list, start, end, target) {
if (start > end) // this is called a base case, look into recursion
return -1
center = (end - start) / 2
if list[center] == target // this is also a base case
return center;
else if list[center] > target
return find(list, start, center-1, target)
else
return find(list, center+1, end, target)
}
And we would run it like so:
list = [ 1 , 3, 7, 9, 12, 15, 17, 21, 28 ]
// need to find the target in the list
find(list, 0, list.length - 1, 3);
this would first look at 12, which is bigger than our target, so then it would split the list in half, look at the middle of the lesser half which is 3 and find it, returning its index. It tends to be more beneficial on larger and larger lists.
I said it uses recursion, which means two things: it will call itself until it finds an answer, and that when it finds the answer, it stops calling itself. There are two main kinds of recursion which you might find out about later, but the most important parts are those two: the recursive step (calling itself) and the base case (when it stops calling itself). Without those two parts something is not recursive.
Use ArrayList. It has a method named as BinarySearch.
I am trying to access the indentation levels of various bulleted list items. So I created a simple function:
private float[] findIndentSpacing(TextRange t, int level) {
if(level == 1) {
RulerLevel rl = t.Parent.Ruler.Levels(2);
//bullet must start at 0 on the first level for now
return new float[2] { 0, rl.LeftMargin * Settings.Scaler() };
} else {
RulerLevel rl = t.Parent.Ruler.Levels[level];
return new float[2] { rl.FirstMargin * Settings.Scaler(), rl.LeftMargin * Settings.Scaler() };
}
}
So that first if statement is a work around. The first level LeftMargin always returns: -2.14748365E+9 for some reason. I've tried to just grab levels after the first and they return actual values. That being said, after one level has been accessed all other levels change and become equal. For example if I try to access: t.Parent.Ruler.Levels[2].FirstMargin, then for some reason t.Parent.Ruler.Levels[3].FirstMargin become the same, and so forth. LeftMargin changes also.
I've tried accessing the ruler object in different ways: by selection, by shape, by text and every way I've thought to try the result is the same.
Ideas?
More info:
I read the following threads, but they are more about writing than reading, but I feel like the problem is similar: PowerPoint Programming: Indentation with Ruler margin levels not working?
http://answers.microsoft.com/en-us/office/forum/office_2007-customize/why-shapetextframerulerlevelsi-cant-set-the-bullet/9eac3e46-b13b-433e-b588-216ead1d9c1a?tab=AllReplies#tabs
I made this one: http://answers.microsoft.com/en-us/office/forum/office_2010-customize/find-bullet-spacing-information-in-an-automated/4525b6b8-6331-4f33-8127-789ea3641589?page=1&tm=1336535132591
In 2007 and 2010 I think you'll need to work with TextRange2 and TextFrame2 objects.
In PPT 2003 and previous, the TextFrame could have 5 indent levels, and all paragraphs at a given indent level shared the same LeftMargin and FirstMargin.
From 2007 on, TextFrames can have up to 9 indent levels, and each paragraph can have its own Left/First margins, independent of the margins set on other paragraphs at the same indent level.
Try this in PPT's VBA IDE. Select the text you're looking at then:
Sub Levels()
Dim oSh as Shape
Dim x As Long
Set oSh = ActiveWindow.Selection.ShapeRange(1)
With oSh.TextFrame2.Ruler
For x = 1 to .Count
Debug.Print .Levels(x).FirstMargin
Debug.Print .Levels(x).LeftMargin
Next
End With
End Sub
I am trying to output all the possible unique integer combinations from 1 to max for a set number of integers. So for 3 integers and a max of 4 I would get:
123
124
134
234
I am doing this with nested for loops but I want to allow the user to input the number of integers at runtime. right now I have
if(numInts >6);
for(int x = 1; x < max; x++);
if(numInts >5);
for(int y = 1; y < max; y++);
...
Is there a way to clean this up so I don't have to write out each possible integer for loop.
PS: I know the code above will not output the requested output. This is for a programing competition so I am not asking for code solutions just the idea that would make this possible.
One word: Recursion.
Looking at your comments on the original post, you want an iterative solution. A recursive solution will be just as fast as an iterative solution when you have a language that supports tail call optimization. But if you're working with Java/C#, again, this isn't available, so here's another way to look at the problem.
You are generating combinations. A combination is just a subset with a certain number of elements. Subsets with small-ish sets can be expressed with bitmasks.
If I have the set [1, 2, 3, 4] and I want to describe the subset [1, 3, 4], I can do so by going through each element and asking "True or False: is this element in the subset?" So, for [1, 3, 4], the result is [True, False, True, True]. If I am working with a set less than 32 (or 64) bytes, I can encode this as an integer: 1011b = 11. This is very compact in memory and computers tend to have very fast bitmath operators.
So what is a combination then, in terms of these binary numbers? If I want all subsets with N members, I can translate that as "I want all numbers with N bits set."
Take [1, 2, 3, 4] as we have been. We want all subsets with 3 elements. How many 4-bit numbers are there with exactly 3 bits set? Answer: 1110b, 1101b, 1011b, and 0111b. If we turn these integers into subsets, we get your solutions: [1, 2, 3], [1, 2, 4], [1, 3, 4], and [2, 3, 4].
You can start thinking in terms of the bits only. You start off with the lowest number with N bits set. That corresponds to a solution. You then start flipping bits one-for-one. In a systematic way such that each iteration always results in the next highest number.
Use recursion, and numInts becomes the depth of your call tree.
Check out combinations on Wikipedia. These are what you are trying to generate.
EDIT: At first, I thought the OP meant permuations. The following code doesn't work for combinations, but I'll keep it here in case someone wants to tweak it to get it to work.
As others have said, this is a problem for which recursion excels at. Let's call your function pick(num, list). Here is some pseudo code.
List pick(Int num, List list)
{
if (num == 1) // base case
{
return list
}
else // recurring case
{
var results = []
foreach (item in list)
{
alteredList = list.copy().remove(item)
results.add([item] + pick(num - 1, alteredList))
}
return results
}
}
Some notes on the above code. Note the two cases. Recursion almost always follows the base-case/recurring-case format. The actual recursion occurs in the line results.add([item] + pick(num - 1, alteredList)), and the key point is that you pass num-1. This means that in each call to pick, num gets smaller and smaller until it reaches 1 (when it reaches 1, it's done).
The variable named alteredList is created as a COPY of list with the current item removed. Most languages have a removed method, but it ALTERS the original list (this is not what you want!!) Recursion works best when variables are immutable (when they aren't altered ever).
Lastly, I want to clarify the line [item] + pick(num - 1, alteredList) a bit. I simply mean create a new list, whose first element is item and the rest of the elements are the list returned by the call pick(num - 1, alteredList). In Lisp, this operation of adding an element to the front of a list is called a cons. This cons operation is extremely powerful in functional languages, where recursion is heavily used, but it is awkward to express in imperative languages, such as Java/C#.
Problems where you would need nested for-loops usually shout for recursion.
Imagine a tree like
<root>
<1>
<1>
<1>
<2>
<3>
<4>
<2>
<1>
<2>
<3>
<4>
...
then walk through the tree (recursivly) and collect the 'valid paths'
internal class Program {
private static void Main(string[] args) {
foreach (var combination in AllCombinations(new[] { 1, 2, 3 })) {
Console.WriteLine(string.Join("", combination.Select(item => item.ToString()).ToArray()));
}
}
private static IEnumerable<IEnumerable<T>> AllCombinations<T>(IEnumerable<T> elements) {
if (elements.Count() == 1) yield return new[] { elements.First() };
else {
foreach (var element in elements) {
foreach (var combination in AllCombinations(elements.Except(new[] { element }))) {
yield return (new[] { element }).Concat<T>(combination);
}
}
}
}
}