在加权无向图中查找一个简单循环,其长度位于给定的用户定义范围内

时间:2012-12-02 05:23:37

标签: algorithm graph routes depth-first-search

已编辑 - 12/03/12 @太平洋标准时间上午1:05

我编写了如下代码。但是,我仍然没有让它返回任何路径。

同样,此代码用于计算路径,用户指定的起始顶点和距离。该程序将返回与指定数据匹配的所有适当路径。

这是我的代码:

vector<vector<Vertex>> Graph::FindPaths(Graph &g, int startingIntersection, float distanceInMiles)
{   
/* A vector which contains vectors which will contain all of the suitable found paths. */
vector<vector<Vertex>> paths;

/* Create an empty set to store the visited nodes. */
unordered_set<int> visited;

/* Vector which will be used to the hold the current path. */
vector<Vertex> CurrentPathList;

/* Will be used to store the currerntVertex being examined. */
Vertex currentVertex;

/* Will be used to store the next vertex ID to be evaluated. */
int nextVertex;

/* Will be used to determine the location of the start ID of a vertex within the VertexList. */
int start;

/* Stack containing the current paths. */
stack<Vertex> currentPaths;

/* CurrentPathDistance will be used to determine the currernt distance of the path. */
float currentPathDistance = 0;

/* The startingIntersection location must be found within the VertexList.  This is because there is
 * no guarantee that the VertexList will hold sequential data.
 *
 * For example, the user inputs a startingIntersection of 73.  The Vertex for intersection #73 may 
 * be located at the 20th position of the VertexList (i.e. VertexList[20]). */
start = g.FindStartingIntersection(g, startingIntersection);

/* Push the startingIntersection onto the stack. */
currentPaths.push(g.VertexList[start]);

/* Continue to iterate through the stack until it is empty.  Once it is empty we have exhaused all
 * possible paths. */
while(!currentPaths.empty())
{
    /* Assign the top value of the stack to the currentVertex. */
    currentVertex = currentPaths.top();

    /* Pop the top element off of the stack. */
    currentPaths.pop();

    /* Check to see if we are back to the startingIntersection.  As a note, if we are just starting, it will 
     * put the startingIntersection into the paths. */
    if(currentVertex.id == startingIntersection)
    {
        /* Add currentVertex to a list. */
        CurrentPathList.push_back(currentVertex);

        /* Find the current path distance. */
        currentPathDistance = FindPathDistance(g, CurrentPathList);

        /* Check the currentPathDistance.  If it is within +/- 1 mile of the specified distance, then place
         * it into the vector of possible paths. */
        if((currentPathDistance + 1 >= distanceInMiles) && (currentPathDistance - 1 <= distanceInMiles))
        {
            paths.push_back(CurrentPathList);
        }
    }
    else /* The ending vertex was not the user specified starting vertex. */
    {
        /* Remove all elements from the stack. */
        while(!currentPaths.empty())
        {
            currentPaths.pop();
        }
    }

    nextVertex = FindUnvisitedNeighbor(g, currentVertex, visited);

    // repeat while current has unvisited neighbors
    while(nextVertex != -1)
    {
        /* Find the new starting vertex. */
        start = g.FindStartingIntersection(g, nextVertex);

        /* Push the startingIntersection onto the stack. */
        currentPaths.push(g.VertexList[start]);

        /* Push the next vertex into the visted list. */
        visited.insert(nextVertex);

        nextVertex = FindUnvisitedNeighbor(g, currentVertex, visited);
    }     
}

/* Return the vector of paths that meet the criteria specified by the user. */
return paths;

FindingUnvistedNeighbor()的代码如下:

int FindUnvisitedNeighbor(Graph &g, Vertex v, unordered_set<int> visited)
{
    /* Traverse through vertex "v"'s EdgeList. */
    for(int i = 0; i + 1 <= v.EdgeList.size(); i++)
    {
        /* Create interator to traverse through the visited list to find a specified vertex. */
        unordered_set<int>::const_iterator got = visited.find(v.EdgeList[i].intersection_ID_second);

        /* The vertex was not found in the visited list. */
        if(got == visited.end())
        {

            return v.EdgeList[i].intersection_ID_second;
        }
    }

    return -1;
}

2 个答案:

答案 0 :(得分:0)

深度优先。

时你必须中止
* path too long (bad)
* vertex already visited (bad)
* starting vertex visited (found a solution)

要检测这些条件,您必须跟踪到目前为止访问的边/顶点

深度冷杉步行看起来像这样(完全未经检查)伪代码 无论如何你应该得到这个想法

edge
    pair of node
    length

node
    list of edge

arrow               // incoming edge, node
    pair of edge, node

path
    list of arrow



check_node(arrow)   // incoming edge, node
    current_path.push(arrow)
    if length(current_path) > limit
        // abort too long
        current_path.pop(arrow)
        return
    if length(current_path) > 0 && current_path.first.node == current_path.last,node
        // found solution
        solutions.push(current_path)  // store the found solution and continue search
        current_path.pop(arrow)
        return
    if node in current_path
        // abort cycle
        current_path.pop(arrow)
        return
    for each edge in node
        // go deeper
        check(arrow(edge, edge.other_node))
    current_path.pop(arrow)
    return


main
    path current_path
    list of path solutions    // will hold all possible solutions after the check

    make_graph

    check_node(NULL, graph.start)

    for each solution in solutions   // print 0 .. n solutions
        print solution

答案 1 :(得分:0)

这似乎是一个基本的算法问题,而不是特定于实现的问题,所以我为算法而不是实际代码提供了详细的高级伪代码。另外,我不懂C ++。如果任何语法/逻辑不清楚,请告诉我,我可以澄清一些。它本质上是一个DFS,但在找到值时不会停止:它继续搜索,并报告该值的所有路径(符合给定的距离标准)。

// Input: Graph G, Vertex start, Integer targetDistance
// Output: Set< List<Vertex> > paths
FindPaths ( G, start, targetDistance ):
    create an empty set, paths
    create an empty set, visited
    create an empty stack, currentPath

    // Iterative Exhaustive DFS
    push start on currentPath
    while ( currentPath is not empty ):
        current = pop ( currentPath )

        if ( current equals start ):
            copy currentPath to a list, L (reversed order doesn't matter)
            // find its weight
            w = FindPathWeight ( L, G )

            if ( w+1 >= targetDistance AND w-1 <= targetDistance ):
                add L to paths

        else if ( current is a dead-end ): drop it completely, it's useless

        x = FindUnvisitedNeighbor ( current, G, visited )
        // repeat while current has unvisited neighbors
        while ( x ):
            push x on currentPath
            add x to visited
            x = FindUnvisitedNeighbor ( current, G, visited )

    return paths
//EndFindPaths


// Input: List path, Graph G
// Output: Integer weight
FindPathWeight ( path, G ):
    Integer weight = 0;

    for each ( Vertex v in path ):

        if ( v is the end of the path ): break

        Consider the next vertex in the list, u
        Find the edge v——u in the graph, call it e
        Get the weight of e, w
        weight = weight + w

    return weight
//EndFindPathWeight


// Input: Vertex v, Graph G, Set visited
// Output: Vertex u (or null, if there are none)
FindUnvisitedNeighbor ( v, G, visited ):

    for each ( Edge v——u in G.EdgeList ):

        if ( u in visited ): continue

        // u is the first unvisited neighbor
        return u

    return null
//EndFindUnvisitedNeighbor