简体   繁体   English

如何在图中找到最长路径

[英]How to find Longest path in graph

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;
}
}

As brz mentioned, this is an NP-complete problem; 正如brz所提到的,这是一个NP完全问题。 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. 从最短路径开始,然后对其执行一些简单的局部扰动以使其更长,例如,如果路径一部分的两个节点都未使用该路径,则将直线更改为C形。 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; 理论CS已经抛弃了你。 you need to turn to practical engineering instead. 您需要转向实用工程。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM