Reputation: 229
I have one problem with my solution for finding longest path in graph. My Programm works very slow when vertices are close to each other. Here is my code please help me.
Test class
public class GraphTest : MonoBehaviour {
// Use this for initialization
void Start () {
const int w = 5;
const int h = 4;
int[,] data = new int[h,w]{
{0,0,0,1,0},
{0,0,0,1,0},
{0,0,1,1,0},
{0,0,0,0,0}};
Map map = new Map(data,w,h);
List<Node> longest = map.longestPath();
Debug.Log("LONGEST " + longest.Count);
//INFO this doing for printing array with steps
int c = longest.Count-1;
foreach(Node n in longest)
data[n.r,n.c] = c--;
string st = "";
for(int i = 0; i < h; i++ )
{
for(int j = 0; j < w; j++)
{
st += data[i,j] + ",";
}
st += "\n";
}
Debug.Log(st);
}
}
Node class
public class Node
{
public int r,c;
public int data;
public Node[] neighbors;
public Node(int r, int c, int data)
{
this.r = r;
this.c = c;
this.data = data;
neighbors = new Node[8];
}
}
Map class for finding paths
public class Map
{
public static int[] xDir = {1,1,1,0,-1,-1,-1,0};
public static int[] yDir = {-1,0,1,1,1,0,-1,-1};
public Node[,] map;
public int[,] mapData;
private int width,height;
private int[,] marks;
public Map(int[,] mapData,int width,int height)
{
this.mapData = mapData;
this.width = width;
this.height = height;
createNodes();
initNeighbors();
}
//INFO create nodes
private void createNodes()
{
map = new Node[height,width];
for(int i = 0; i < height; i++ )
{
for(int j = 0; j < width; j++)
{
map[i,j] = new Node(i,j,mapData[i,j]);
}
}
}
//INFO assign neighbor nodes
private void initNeighbors()
{
for(int i = 0; i < height; i++ )
{
for(int j = 0; j < width; j++)
{
for(int k = 0; k < 8; k++)
{
if(inRange(i+yDir[k],j+xDir[k]))
{
map[i,j].neighbors[k] = map[i+yDir[k],j+xDir[k]];
}
}
}
}
}
private bool inRange(int r, int c)
{
return r < height && r >= 0 && c < width && c >= 0;
}
public List<Node> longestPath()
{
marks = new int[height,width];
List<Node> nodes = new List<Node>();
int c = dfs(map[0,0],nodes);
//INFO Iterasions count
Debug.Log("COUNT " + c);
return nodes;
}
private int dfs(Node node, List<Node> nodes)
{
int i = 1;
List<Node> longest = new List<Node>();
List<Node> list = null;
marks[node.r,node.c] = 1;
for(int n = 0; n < 8; n++)
{
//INFO if the neighbor node is not null and same type with parent node do dfs for neighbor node
if(node.neighbors[n] != null &&
marks[node.neighbors[n].r,node.neighbors[n].c] == 0 &&
node.neighbors[n].data == node.data)
{
list = new List<Node>();
i += dfs(node.neighbors[n],list);
//INFO if the found nodes count is more than previous nodes count set new nodes to best nodes
if(list.Count > longest.Count)
longest = list;
}
}
marks[node.r,node.c] = 0;
longest.Add(node);
nodes.AddRange(longest);
return i;
}
}
Upvotes: 0
Views: 2327
Reputation: 41532
As brz mentioned, this is an NP-complete problem; you won't be able to find a solution that is both efficient and guaranteed optimal. (Or, if you do, every programmer in the world will buy you a beer.)
That's not to say you can't do anything about it. Concentrate on the general shape of your particular use case, and any peculiarities, and decide how much inaccuracy you're willing to deal with.
The first thing you can do is look for a bottleneck -- a pair of adjacent traversable cells such that there is no path between them other than the direct one, and the start and goal nodes are on opposite sides of the pair. For the grid case, you can look at the cells which have exactly two neighbors, and then check for bottlenecks against those two neighbors. If you find a bottleneck, congratulations -- you've cut your problem into two subproblems, each of which will be much faster to solve.
You can also try randomized approaches, such as simulated annealing. Start with the shortest path, then perform some simple localized perturbation on it to make it longer, such as changing a straight line into a C-shape if the two nodes to one side of a part of the path are both unused by the path. Keep doing that until you can't make it any longer, then pick two nodes from your path at random, replace the path between them with the shortest path, re-elongate it, and consider taking that as the new path.
Ultimately, you need to remember that this is not a problem you can solve in its most theoretical, general form. You can concentrate on special cases, and you can relax your requirement of exact optimality. Theoretical CS has abandoned you; you need to turn to practical engineering instead.
Upvotes: 2