Algorithm Can';t弄明白这个图形表示法(需要算法!)

Algorithm Can';t弄明白这个图形表示法(需要算法!),algorithm,graph,Algorithm,Graph,在没有任何适当的解决方案的情况下,我一直在努力使这个图形演示变得有意义。也许有人能想出办法 我有一个连通的、无圈图的表示,其形式如下: 逐个删除阶数为1(只有一条边)的顶点 如果有多个选项,则具有最小值的顶点将被删除 移除顶点后,它旁边的顶点将被标记 这将一直持续到图形只剩下一个顶点为止 下面是一个示例图: 2 3 \ / 5 1 \ / 4 这就是演示文稿的形式: 2 3 3 \ /

在没有任何适当的解决方案的情况下,我一直在努力使这个图形演示变得有意义。也许有人能想出办法

我有一个连通的、无圈图的表示,其形式如下:

  • 逐个删除阶数为1(只有一条边)的顶点
  • 如果有多个选项,则具有最小值的顶点将被删除
  • 移除顶点后,它旁边的顶点将被标记
  • 这将一直持续到图形只剩下一个顶点为止
下面是一个示例图:

    2   3
     \ /
  5   1
   \ /
    4
这就是演示文稿的形式:

    2   3            3
     \ /            /
  5   1    =>  5   1    =>  5   1  =>  5    =>  5
   \ /          \ /          \ /        \
    4            4            4          4


1. Remove vertex two and mark one.

2. Remove vertex three and mark one.

3. Remove vertex one and mark four.

4. Remove vertex four and mark five.
因此,该图的表示形式为:

1 1 4 5
问题是,如何将此演示文稿转换为邻接矩阵或邻接列表? F.e.对于1 1 4 5,邻接列表如下所示:

1: 2 3 4
2: 1
3: 1
4: 1 5
5: 4
谢谢大家!

可以使用以下技术将“演示”(在您的示例中为1 4 5)转换回图形(从您上面的评论来看,这是我认为您正在努力解决的问题)。然后,您可以简单地生成一个邻接矩阵/列表

该技术依赖于关键假设,即图中的节点标记为1-N(图中有N个节点)。如果不是这样,则根本不可能重建原始图形,因为您永远无法确定第一个删除节点的标识

  • 请注意,演示文稿中有4个项目。因此,图中有5个节点
  • 从演示文稿的结尾开始向后操作
  • 移除最后一个节点时,剩下的节点为5。因此,图表看起来像

    5-?

  • 删除上一项时,标记为4。因此,原来的问号实际上必须是节点4,我们有一个新的未知节点

    5-4-?

  • 删除上一项时,标记为1。所以呢??必须是1,并且有一个新的未知节点

    5-4-1-A

  • 最后,当删除前一项时,标记为1。我们已经有一个节点1,所以我们必须连接到它

     5 - 4 - 1 +- ?A
               |
               += ?B
    
  • 我们已经完成了对输入的解析。现在我们只需要给优秀的学生贴上标签。我们知道值是2和3,因为上面提到的假设是节点被标记为1-N,我们已经有了1、2和5。因为最低值节点首先被删除(当将图形转换为表示时),所以在将表示转换为图形时,它们最后被添加。那么?A=3和?B=2。(在本例中,这并不重要,但在一般情况下,它确实重要。)最后的图表如下所示

     5 - 4 - 1 +- 3
               |
               += 2
    
    …这很好,因为这与我们的起点相同

  • 由此,您可以迭代节点并生成邻接矩阵。或者,so可以在执行过程中生成邻接列表/矩阵(这可能更有效,但会稍微混淆实现)


    正如David在上面指出的,这与a非常相似(但不完全相同),a在剩下2个节点时停止(而不仅仅是1个节点)。链接文章提供了一种高效的伪代码算法,可以通过跳过最后一步(链接最后两个节点)进行调整。

    以下是python中的简单实现:

    from collections import defaultdict
    
    prufer_sequence = [1, 1, 4, 5]
    all_vertices = range(1, len(prufer_sequence) + 2)
    
    adjacency = defaultdict(list)
    for vertex in prufer_sequence:
        searched_vertex = filter(lambda v: v != vertex, all_vertices)[0]
        all_vertices.remove(searched_vertex)
        adjacency[vertex].append(searched_vertex)
        adjacency[searched_vertex].append(vertex)
    
    print adjacency
    
    和输出:

    defaultdict(<type 'list'>, {1: [2, 3, 4], 2: [1], 3: [1], 4: [1, 5], 5: [4]})
    
    defaultdict(,{1:[2,3,4],2:[1],3:[1],4:[1,5],5:[4]})
    
    我想出了这个算法。很像这样,但就像安德鲁说的,我把最后一部分忘了。hashmap用于邻接列表,arraylist k用于表示

    public static HashMap<Integer, HashSet<Integer>> toGraph(ArrayList<Integer> k) {
            HashMap<Integer, HashSet<Integer>> hm = new HashMap<Integer, HashSet<Integer>>();
            for(int i=1; i<=k.size()+1; i++){
                hm.put(i, new HashSet<Integer>());
            }
            int degree[] = new int[k.size()+1];
            for(int i=0; i<degree.length; i++){
                degree[i]=1;
            }
            for(int a : k){
                degree[a-1]++;
            }
            for(int n : k){
                for(int j : hm.keySet()){
                    if(degree[j-1]==1){
                        hm.get(j).add(n);
                        hm.get(n).add(j);
                        degree[n-1]--;
                        degree[j-1]--;
                        break;
                    }
                }
            }
            return hm;
        }
    
    publicstatichashmap-toGraph(arraylistk){
    HashMap hm=新的HashMap();
    
    对于(int i=1;iAh!由于原始问题中的信息不足(特别是info:tree将有
    1到n+1
    节点,其中
    n
    是输入数组的长度),我尝试以更难的方式解决它!无论如何,这是我的Prufer树生成实现,可能会有所帮助:-?:

    #include <stdio.h>
    #include <vector>
    #include <memory.h>
    using namespace std;
    
    struct Node {
        int N;
        vector<int>list;
        Node() {
            N=-1;
            list.clear();
        }
    };
    
    vector<Node> convertPruferToTree(vector<int>& input) {
        int n = input.size()+1;
        vector<Node> T;
        int *degree = new int[n+1];
        for (int i=1; i<=n; i++) {
            Node tmp;
            tmp.N = i;
            T.push_back(tmp);
            degree[i]=1;
        }
        //printf("n: %d\n", n);
        for (int i=0; i<input.size()-1; i++) {
            degree[input[i]]++;
        }
    
        for (int i=0; i<input.size()-1; i++) {
            for (int j=1; j<=n; j++) {
                if (degree[j]==1) {
                    T[j-1].list.push_back(input[i]);
                    T[input[i]-1].list.push_back(j);
                    degree[input[i]]--;
                    degree[j]--;
                    break;
                }
            }
        }
        int u=0, v=0;
    
        for (int i=1; i<=n; i++) {
            if (degree[i]==1) {
                if (u==0) u=i;
                else {
                     v = i;
                    break;
                }
            }
        }
        //printf("u: %d v: %d\n", u, v);
        T[u-1].list.push_back(v);
        T[v-1].list.push_back(u);
        delete []degree;
        return T;
    }
    
    int main () {
        vector <int> input;
        int n,v;
        scanf("%d", &n);
        while(n--) {
            scanf("%d", &v);
            input.push_back(v);
        }
        vector<Node> adjList = convertPruferToTree(input);
        Node tmp;
        for (int i=0; i<adjList.size(); i++) {
            tmp = adjList[i];
            printf("%2d: ", tmp.N);
            for (int j=0; j<tmp.list.size(); j++) {
                printf("%2d ", tmp.list[j]);
            }
            printf("\n");
        }
        return 0;
    }
    
    #包括
    #包括
    #包括
    使用名称空间std;
    结构节点{
    int N;
    矢量表;
    节点(){
    N=-1;
    list.clear();
    }
    };
    矢量转换器PRUFERTOTREE(矢量和输入){
    int n=input.size()+1;
    向量T;
    整数*度=新整数[n+1];
    
    对于(inti=1;iIt在我看来似乎是树,我认为你有一个算法(你的文本描述是什么,真的)。你需要一个实现。这是一个小工作,是的,但你确实在这里提到了你所需要的一切——除了编程语言和实现的开始。你必须先做这件事,然后再回来。问题不是如何将图形转换成这个演示,问题是如何将它转换成图形。我不认为这是一个问题脚本是我的工作算法。如果你有一个解决方案,你能给我一点启发吗?这似乎是可行的。只要把它转换成java,但我想我可以做到。非常感谢!