在2个顶点之间找到DAG(未加权)中的最短路径

时间:2010-06-30 10:50:46

标签: java graph path directed-acyclic-graphs

在Floyd-Warshall / Dijkstra回复洪水进来之前,请让我解释一下情况,因为我确定任何一种算法都可以针对这种情况进行调整,而且必须是因为这不是一个玩具示例程序(请注意) ,在java中,所以必须保持内存管理的可管理性)

我所拥有的是从节点0到节点n生成的Web图,节点3无法链接到节点5,因为当节点3选择它的 out links 时节点5不存在。每个“节点”表示为in_neighbours [nodeID]和out_neighbours [nodeID]表示nodeId = 3,所以我们讨论的是节点3.还要注意in_ / out_都是排序的,(in_自然排序为5将选择它的链接全部一次,只有6将选择out_links所以3的in_'s永远不会包含{6,5,7})和ofc都可以包含重复。 (in / out是大小为n的ArrayList数组,其中out_总是大小为d或m,其中n与用户在启动时指定)

没有重量。我必须做的是找到averageDistance()

public double getAvgDistance() {
    int sum = 0;        

    for (int i=1; i<n; i++) {
        for (int j=0; j < i; j++) {
            sum += dist(i, j);             // there are duplicates, make sure i skip 
        }
    }

    return (double)sum / (double)(  ((n*(n-1)) / 2)  );
}

到目前为止,我所拥有的是最好的情况。注意我只想找到j&amp;之间的距离。我,不是所有距离同时(没有足够的记忆,它将在m = 20 d = 1 000 000时进行测试)

private int dist(int i, int j) {
    int dist = 0;

    for (int link : in_neighbours[j]) {
        System.out.print("\nIs "+j+" linked to by "+i);
        if (out_neighbours[i].contains(link)) {
            System.out.print(" - yes!");
            dist = 1;
        }
    }

    return dist;
}

所以即时通讯询问是否“更新鲜”(此时图表已完成)节点i直接链接到任何较老的伙伴,如果是这样,距离是1跳。

如果节点向后移动,它只是我或“最短”路径始终是第一个找到的路径吗?

我如何检查它是否不是1,基本情况后的“其他”?我的数学相当弱,请温柔:) 任何提示如何利用链接排序的事实?

这不是家庭作业或者我试图欺骗的东西,它不是关于代码本身,而是必须是一个有用的工具,“学习”一路走来。< / p>

这里是图表在m = 7 n = 13的链接中看起来如何看出nodeID,out链接,(注意0周期就是图表的初始化方式):

0 | 0 0 0 0 0 0 0  | 0 0 0 0 0 0 0 1 1 1 1 1 1 1 2 2 2 2 2 3 4 5 6 6 7 8 9 
1 | 0 0 0 0 0 0 0  | 2 2 3 4 5 5 8 12 
2 | 0 0 0 0 0 1 1  | 3 3 3 3 3 4 4 4 6 7 8 10 
3 | 0 1 2 2 2 2 2  | 4 4 5 5 6 6 7 11 
4 | 0 1 2 2 2 3 3  | 5 5 6 8 9 10 
5 | 0 1 1 3 3 4 4  | 6 7 8 9 9 11 12 
6 | 0 0 2 3 3 4 5  | 7 7 7 8 9 9 12 
7 | 0 2 3 5 6 6 6  | 8 9 10 11 11 12 
8 | 0 1 2 4 5 6 7  | 10 10 10 11 12 
9 | 0 4 5 5 6 6 7  | 10 11 11 
10 | 2 4 7 8 8 8 9  | 12 12 
11 | 3 5 7 7 8 9 9  | 
12 | 1 5 6 7 8 10 10  | 

对于令人痛苦的长篇阅读感到抱歉。 编辑:方法中的代码错误,我认为这是正确的。

dist nr2的修订版,试着找出是否有路径:

private int dist(int i, int j) {
    int dist = 0, c = 0, count = 0;
    boolean linkExists = false;

    for (int link : in_neighbours[j]) {

        //System.out.print("\nIs "+j+" linked to by "+i);
        if (out_neighbours[i].contains(link)) {

            //System.out.print(" - yes!");
            dist = 1; // there is a direct link

        } else {

            while ( c < j ) {
                // if there's a path from 0 up to j, check if 'i' links to a node which eventually links to 'j'
                if (out_neighbours[i].contains(c) && 
                        (out_neighbours[c].contains(link) || in_neighbours[c].contains(link) )) {

                    count++; // yes. and this is one node we had to step through to get closer
                    linkExists = true;
                } else {
                    linkExists = false; // unreachable, the path was interrupted somewhere on the way
                    break;
                }
                c++; 
            }

            if (linkExists) {
                dist = count-1; // as 2 nodes are linked with 1 edge
            } else {
                dist = 0; // no path was found
            }
        }


    }

    return dist;
}

1 个答案:

答案 0 :(得分:2)

由于您的模型中所有边都具有相同的权重,因此您可以使用BFS搜索来查找从S到T的最短路径。

这是一个迭代过程,从set#0开始,只包含源节点({S})。 在每个步骤i,您通过在一个步骤中查找可从集合(i-1)实现的所有节点来创建集合#i。

迭代在两种情况下终止:

1)当你检测到#k包含T.时,你会返回k-1。

2)当集合为空时,表示两个节点无法访问。

内存消耗大约是节点数量的两倍,因为在每一步中你使用两组(i-1和i),以节点总数为界。

- 编辑 -

这是一个可能的实现(我对它进行了一些测试):

private Integer getDist(int i, int j) {
    Set<Integer> currentSet = new HashSet<Integer>();
    currentSet.add(i);
    int dist = 0;
    while (true) {
        Set<Integer> nextSet = new HashSet<Integer>();
        for (Integer currNode : currentSet)
            nextSet.addAll(out[currNode]);

        if (nextSet.isEmpty())
            return null; //i.e. infinite
        if (nextSet.contains(j))
            return dist;
        dist++;
        currentSet = nextSet; 
    }
}

该实现假定 out 中的定义为List&lt; Integer&gt; [],并且节点由从0开始的数字标识。最小距离计为路径中的中间节点数,而不是边数。

列表中的副本不会破坏任何内容,但它们与算法无关。