问题
I have a problem to find all possible paths.
a a a b
b a a a
a b b a
Traveling from starting point at 0,0 to end point at 2,3. I need to get all possible paths.
Possible moves that I can do are moving down and moving right.
Let me tell you where I am stuck. I am trying to do with a recursive function . Starting with point at 0,0 and moving towards right whenever I can and moving down only when I must.
My recursive function :
public static move(int i,int j)
{
if(possible(x,y+1))
{
move(x,y+1);
move(x+1,y);
}
}
public static bool possible(int i,int j)
{
if((i >=0 && i<3 ) && (j>=0 && j<4))
return true;
else
return false;
}
Not sure about my recursive move function. Still need to expand it . I am not getting exactly how I should implement .
I am able to traverse upto the corner node using that move method but I need that function to retrace back whenever all possible moves from the corner top right point(0,4) is reached.
回答1:
You need to stop and take a big step back.
The first step should be coming up with the signature of the method. What is the problem statement?
Find all possible paths
Not mentioned: starting from a particular coordinate.
So the method needs to return a set of paths:
static Set<Path> AllPaths(Coordinate start) { /* a miracle happens */ }
OK, now we're getting somewhere; now it is clear what we need. We need a set of things, and we need a path, and we need coordinates.
What's a coordinate? a pair of integers:
struct Coordinate
{
public int X { get; }
public int Y { get; }
public Coordinate(int x, int y) : this()
{
this.X = x;
this.Y = y;
}
}
Done. So pop the stack; what is a path? A path can be empty, or it can be a first step followed by a path:
sealed class Path
{
private Path() { }
private Path(Coordinate first, Path rest)
{
this.first = first;
this.rest = rest;
}
public static readonly Path Empty = new Path();
private Coordinate first;
private Path rest;
public bool IsEmpty => this == Empty;
public Coordinate First
{
get
{
if (this.IsEmpty) throw new Exception("empty!");
return first;
}
}
public Path Rest
{
get
{
if (this.IsEmpty) throw new Exception("empty!");
return rest;
}
}
public Path Append(Coordinate c) => new Path(c, this);
public IEnumerable<Coordinate> Coordinates()
{
var current = this;
while(!current.IsEmpty)
{
yield return current;
current = current.Rest;
}
}
}
Done.
Now you implement Set<T>
. You will need to have the operations "all items" and "union this set with another to produce a third". Make sure that sets are immutable. You don't want to change a set when you add new items to it; you want a different set. The same way you don't change 3 into 4 when you add 1; 3 and 4 are different numbers.
Now you have all the tools you need to actually solve the problem; now you can implement
static Set<Path> AllPaths(Coordinate start)
{
/* a miracle happens */
}
So how does this work? Remember that all recursive functions have the same form:
- Solve the trivial case
- If we're not in a trivial case, reduce the problem to a smaller case, solve it recursively, and combine solutions.
So what is the trivial case?
static Set<Path> AllPaths(Coordinate start)
{
/* Trivial case: if the start coordinate is at the end already
then the set consists of one empty path. */
Implement that.
And what is the recursive case?
/* Recursive case: if we're not at the end then either we can go
right, go down, or both. Solve the problem recursively for
right and / or down, union the results together, and add the
current coordinate to the top of each path, and return the
resulting set. */
Implement that.
The lessons here are:
- Make a list of all the nouns in the problem: set, path, coordinate, and so on.
- Make a type that represents each one. Keep it simple, and make sure you implement exactly the operations each type needs.
- Now that you have an abstraction implemented for each noun you can start designing algorithms that use the abstractions, with confidence that they will work.
- Remember the basic rules of recursion: solve the base case if you can; if not, solve the smaller recursive cases and combine the solutions.
回答2:
public void MoveUp(Object sender, MoveEventArgs e)
{
if (CanMoveUp(e.CurrentPosition.Y)) ...
}
public void MoveDown(Object sender, MoveEventArgs e)
{
if (CanMoveDown(e.CurrentPosition.Y)) ...
}
public void MoveLeft(Object sender, MoveEventArgs e)
{
if (CanMoveLeft(e.CurrentPosition.X)) ...
}
public void MoveRight(Object sender, MoveEventArgs e)
{
if (CanMoveRight(e.CurrentPosition.X)) ...
}
private bool CanMoveUp(double y) => (y - 1) > 0;
private bool CanMoveDown(double y) => (y + 1) < 4;
private bool CanMoveLeft(double x) => (x - 1) > 0;
private bool CanMoveRight(double x) => (x + 1) < 4;
These Values may not be right, but the code is reusable and easily maintainable in the event you would want to add any other possible barriers to movement you could easily add the additions to each method.
回答3:
It's hard not to give away the farm and be helpful. You should break down the decision logic to 3 boundary functions
inBoundsX x
// return true if x is in bounds, false otherwise
inBoundsY y
// return true if y is in bounds, false otherwise
inBoundsXY x,y
// return true if x and y are in bounds, false otherwise
Your recursive function should always validate the initial state it's given, then decide which way to move next.
move x,y
if inBoundsXY x,y
print I am here x,y
// use InboundsX, InboundsY to decide next move.
来源:https://stackoverflow.com/questions/41409100/finding-all-possible-paths