📜  查找无向图的 k 核

📅  最后修改于: 2022-05-13 01:57:53.937000             🧑  作者: Mango

查找无向图的 k 核

给定一个图 G 和一个整数 K,图的 K 核是在所有度数小于 k 的顶点被移除后留下的连通分量(来源 wiki)

例子:

Input : Adjacency list representation of graph shown
        on left side of below diagram
Output: K-Cores : 
[2] -> 3 -> 4 -> 6
[3] -> 2 -> 4 -> 6 -> 7
[4] -> 2 -> 3 -> 6 -> 7
[6] -> 2 -> 3 -> 4 -> 7
[7] -> 3 -> 4 -> 6

内核


我们强烈建议您最小化您的浏览器并首先自己尝试。
查找 k 核图的标准算法是从输入图中删除度数小于 - 'K' 的所有顶点。我们必须小心,删除一个顶点会降低与其相邻的所有顶点的度数,因此相邻顶点的度数也可能低于-'K'。因此,我们可能还必须删除这些顶点。这个过程可能/可能不会进行,直到图中没有顶点为止。

为了实现上述算法,我们在输入图上做一个修改的 DFS 并删除所有度数小于'K'的顶点,然后更新所有相邻顶点的度数,如果它们的度数低于'K',我们也将它们删除.

下面是上述想法的实现。请注意,以下程序仅打印 k 个核心的顶点,但由于我们修改了邻接列表,因此可以轻松扩展以打印完整的 k 个核心。

C++14
// C++ program to find K-Cores of a graph
#include
using namespace std;
 
// This class represents a undirected graph using adjacency
// list representation
class Graph
{
    int V; // No. of vertices
 
    // Pointer to an array containing adjacency lists
    list *adj;
public:
    Graph(int V); // Constructor
 
    // function to add an edge to graph
    void addEdge(int u, int v);
 
    // A recursive function to print DFS starting from v
    bool DFSUtil(int, vector &, vector &, int k);
 
    // prints k-Cores of given graph
    void printKCores(int k);
};
 
// A recursive function to print DFS starting from v.
// It returns true if degree of v after processing is less
// than k else false
// It also updates degree of adjacent if degree of v
// is less than k. And if degree of a processed adjacent
// becomes less than k, then it reduces of degree of v also,
bool Graph::DFSUtil(int v, vector &visited,
                    vector &vDegree, int k)
{
    // Mark the current node as visited and print it
    visited[v] = true;
 
    // Recur for all the vertices adjacent to this vertex
    list::iterator i;
    for (i = adj[v].begin(); i != adj[v].end(); ++i)
    {
        // degree of v is less than k, then degree of adjacent
        // must be reduced
        if (vDegree[v] < k)
            vDegree[*i]--;
 
        // If adjacent is not processed, process it
        if (!visited[*i])
        {
            // If degree of adjacent after processing becomes
            // less than k, then reduce degree of v also.
            DFSUtil(*i, visited, vDegree, k);
        }
    }
 
    // Return true if degree of v is less than k
    return (vDegree[v] < k);
}
 
Graph::Graph(int V)
{
    this->V = V;
    adj = new list[V];
}
 
void Graph::addEdge(int u, int v)
{
    adj[u].push_back(v);
    adj[v].push_back(u);
}
 
// Prints k cores of an undirected graph
void Graph::printKCores(int k)
{
    // INITIALIZATION
    // Mark all the vertices as not visited and not
    // processed.
    vector visited(V, false);
    vector processed(V, false);
 
    int mindeg = INT_MAX;
    int startvertex;
 
    // Store degrees of all vertices
    vector vDegree(V);
    for (int i=0; i= K after BFS
        if (vDegree[v] >= k)
        {
            cout << "\n[" << v << "]";
 
            // Traverse adjacency list of v and print only
            // those adjacent which have vDegree >= k after
            // BFS.
            list::iterator itr;
            for (itr = adj[v].begin(); itr != adj[v].end(); ++itr)
                if (vDegree[*itr] >= k)
                    cout << " -> " << *itr;
        }
    }
}
 
// Driver program to test methods of graph class
int main()
{
    // Create a graph given in the above diagram
    int k = 3;
    Graph g1(9);
    g1.addEdge(0, 1);
    g1.addEdge(0, 2);
    g1.addEdge(1, 2);
    g1.addEdge(1, 5);
    g1.addEdge(2, 3);
    g1.addEdge(2, 4);
    g1.addEdge(2, 5);
    g1.addEdge(2, 6);
    g1.addEdge(3, 4);
    g1.addEdge(3, 6);
    g1.addEdge(3, 7);
    g1.addEdge(4, 6);
    g1.addEdge(4, 7);
    g1.addEdge(5, 6);
    g1.addEdge(5, 8);
    g1.addEdge(6, 7);
    g1.addEdge(6, 8);
    g1.printKCores(k);
 
    cout << endl << endl;
 
    Graph g2(13);
    g2.addEdge(0, 1);
    g2.addEdge(0, 2);
    g2.addEdge(0, 3);
    g2.addEdge(1, 4);
    g2.addEdge(1, 5);
    g2.addEdge(1, 6);
    g2.addEdge(2, 7);
    g2.addEdge(2, 8);
    g2.addEdge(2, 9);
    g2.addEdge(3, 10);
    g2.addEdge(3, 11);
    g2.addEdge(3, 12);
    g2.printKCores(k);
 
    return 0;
}


Java
// Java program to find K-Cores of a graph
import java.util.*;
 
class GFG
{
 
    // This class represents a undirected graph using adjacency
    // list representation
    static class Graph
    {
        int V; // No. of vertices
 
        // Pointer to an array containing adjacency lists
        Vector[] adj;
 
        @SuppressWarnings("unchecked")
        Graph(int V)
        {
            this.V = V;
            this.adj = new Vector[V];
 
            for (int i = 0; i < V; i++)
                adj[i] = new Vector<>();
        }
 
        // function to add an edge to graph
        void addEdge(int u, int v)
        {
            this.adj[u].add(v);
            this.adj[v].add(u);
        }
 
        // A recursive function to print DFS starting from v.
        // It returns true if degree of v after processing is less
        // than k else false
        // It also updates degree of adjacent if degree of v
        // is less than k. And if degree of a processed adjacent
        // becomes less than k, then it reduces of degree of v also,
        boolean DFSUtil(int v, boolean[] visited, int[] vDegree, int k)
        {
 
            // Mark the current node as visited and print it
            visited[v] = true;
 
            // Recur for all the vertices adjacent to this vertex
            for (int i : adj[v])
            {
 
                // degree of v is less than k, then degree of adjacent
                // must be reduced
                if (vDegree[v] < k)
                    vDegree[i]--;
 
                // If adjacent is not processed, process it
                if (!visited[i])
                {
 
                    // If degree of adjacent after processing becomes
                    // less than k, then reduce degree of v also.
                    DFSUtil(i, visited, vDegree, k);
                }
            }
 
            // Return true if degree of v is less than k
            return (vDegree[v] < k);
        }
 
        // Prints k cores of an undirected graph
        void printKCores(int k)
        {
 
            // INITIALIZATION
            // Mark all the vertices as not visited and not
            // processed.
            boolean[] visited = new boolean[V];
            boolean[] processed = new boolean[V];
            Arrays.fill(visited, false);
            Arrays.fill(processed, false);
 
            int mindeg = Integer.MAX_VALUE;
            int startvertex = 0;
 
            // Store degrees of all vertices
            int[] vDegree = new int[V];
            for (int i = 0; i < V; i++)
            {
                vDegree[i] = adj[i].size();
 
                if (vDegree[i] < mindeg)
                {
                    mindeg = vDegree[i];
                    startvertex = i;
                }
            }
            DFSUtil(startvertex, visited, vDegree, k);
 
            // DFS traversal to update degrees of all
            // vertices.
            for (int i = 0; i < V; i++)
                if (!visited[i])
                    DFSUtil(i, visited, vDegree, k);
 
            // PRINTING K CORES
            System.out.println("K-Cores : ");
            for (int v = 0; v < V; v++)
            {
 
                // Only considering those vertices which have degree
                // >= K after BFS
                if (vDegree[v] >= k)
                {
                    System.out.printf("\n[%d]", v);
 
                    // Traverse adjacency list of v and print only
                    // those adjacent which have vDegree >= k after
                    // BFS.
                    for (int i : adj[v])
                        if (vDegree[i] >= k)
                            System.out.printf(" -> %d", i);
                }
            }
        }
    }
 
    // Driver Code
    public static void main(String[] args)
    {
 
        // Create a graph given in the above diagram
        int k = 3;
        Graph g1 = new Graph(9);
        g1.addEdge(0, 1);
        g1.addEdge(0, 2);
        g1.addEdge(1, 2);
        g1.addEdge(1, 5);
        g1.addEdge(2, 3);
        g1.addEdge(2, 4);
        g1.addEdge(2, 5);
        g1.addEdge(2, 6);
        g1.addEdge(3, 4);
        g1.addEdge(3, 6);
        g1.addEdge(3, 7);
        g1.addEdge(4, 6);
        g1.addEdge(4, 7);
        g1.addEdge(5, 6);
        g1.addEdge(5, 8);
        g1.addEdge(6, 7);
        g1.addEdge(6, 8);
        g1.printKCores(k);
 
        System.out.println();
 
        Graph g2 = new Graph(13);
        g2.addEdge(0, 1);
        g2.addEdge(0, 2);
        g2.addEdge(0, 3);
        g2.addEdge(1, 4);
        g2.addEdge(1, 5);
        g2.addEdge(1, 6);
        g2.addEdge(2, 7);
        g2.addEdge(2, 8);
        g2.addEdge(2, 9);
        g2.addEdge(3, 10);
        g2.addEdge(3, 11);
        g2.addEdge(3, 12);
        g2.printKCores(k);
    }
}
 
// This code is contributed by
// sanjeev2552


Python3
#saurabh_jain861
# Python program to find K-Cores of a graph
from collections import defaultdict
 
# This class represents a undirected graph using adjacency
# list representation
 
 
class Graph:
 
    def __init__(self):
 
        # default dictionary to store graph
        self.graph = defaultdict(list)
 
    # function to add an edge to undirected graph
    def addEdge(self, u, v):
        self.graph[u].append(v)
        self.graph[v].append(u)
 
    # A recursive function to call DFS starting from v.
    # It returns true if vDegree of v after processing is less
    # than k else false
    # It also updates vDegree of adjacent if vDegree of v
    # is less than k. And if vDegree of a processed adjacent
    # becomes less than k, then it reduces of vDegree of v also,
    def DFSUtil(self, v, visited, vDegree, k):
 
        # Mark the current node as visited
        visited.add(v)
 
        # Recur for all the vertices adjacent to this vertex
        for i in self.graph[v]:
 
            # vDegree of v is less than k, then vDegree of
            # adjacent must be reduced
            if vDegree[v] < k:
                vDegree[i] = vDegree[i] - 1
 
            # If adjacent is not processed, process it
            if i not in visited:
 
                # If vDegree of adjacent after processing becomes
                # less than k, then reduce vDegree of v also
                self.DFSUtil(i, visited, vDegree, k)
 
    def PrintKCores(self, k):
 
        visit = set()
        degree = defaultdict(lambda: 0)
 
        for i in list(self.graph):
            degree[i] = len(self.graph[i])
 
        for i in list(self.graph):
 
            if i not in visit:
                self.DFSUtil(i, visit, degree, k)
 
        # print(degree)
        # print(self.graph)
 
        for i in list(self.graph):
 
            if degree[i] >= k:
                print(str("\n [ ") + str(i) + str(" ]"), end=" ")
 
                for j in self.graph[i]:
                    if degree[j] >= k:
                        print("-> " + str(j), end=" ")
 
                print()
 
 
k = 3
g1 = Graph()
g1.addEdge(0, 1)
g1.addEdge(0, 2)
g1.addEdge(1, 2)
g1.addEdge(1, 5)
g1.addEdge(2, 3)
g1.addEdge(2, 4)
g1.addEdge(2, 5)
g1.addEdge(2, 6)
g1.addEdge(3, 4)
g1.addEdge(3, 6)
g1.addEdge(3, 7)
g1.addEdge(4, 6)
g1.addEdge(4, 7)
g1.addEdge(5, 6)
g1.addEdge(5, 8)
g1.addEdge(6, 7)
g1.addEdge(6, 8)
g1.PrintKCores(k)


C#
// C# program to find K-Cores of a graph
using System;
using System.Collections.Generic;
 
class GFG{
 
// This class represents a undirected
// graph using adjacency list
// representation
public class Graph
{
     
    // No. of vertices
    int V;
 
    // Pointer to an array containing
    // adjacency lists
    List[] adj;
 
    public Graph(int V)
    {
        this.V = V;
        this.adj = new List[V];
 
        for(int i = 0; i < V; i++)
            adj[i] = new List();
    }
 
    // Function to add an edge to graph
    public void addEdge(int u, int v)
    {
        this.adj[u].Add(v);
        this.adj[v].Add(u);
    }
 
    // A recursive function to print DFS
    // starting from v. It returns true
    // if degree of v after processing
    // is less than k else false
    // It also updates degree of adjacent
    // if degree of v is less than k. And
    // if degree of a processed adjacent
    // becomes less than k, then it reduces
    // of degree of v also,
    bool DFSUtil(int v, bool[] visited,
                 int[] vDegree, int k)
    {
         
        // Mark the current node as
        // visited and print it
        visited[v] = true;
 
        // Recur for all the vertices
        // adjacent to this vertex
        foreach (int i in adj[v])
        {
             
            // Degree of v is less than k,
            // then degree of adjacent
            // must be reduced
            if (vDegree[v] < k)
                vDegree[i]--;
 
            // If adjacent is not
            // processed, process it
            if (!visited[i])
            {
                 
                // If degree of adjacent after
                // processing becomes less than
                // k, then reduce degree of v also.
                DFSUtil(i, visited, vDegree, k);
            }
        }
 
        // Return true if degree of
        // v is less than k
        return (vDegree[v] < k);
    }
 
    // Prints k cores of an undirected graph
    public void printKCores(int k)
    {
         
        // INITIALIZATION
        // Mark all the vertices as not
        // visited and not processed.
        bool[] visited = new bool[V];
        //bool[] processed = new bool[V];
   
        int mindeg = int.MaxValue;
        int startvertex = 0;
 
        // Store degrees of all vertices
        int[] vDegree = new int[V];
         
        for(int i = 0; i < V; i++)
        {
            vDegree[i] = adj[i].Count;
             
            if (vDegree[i] < mindeg)
            {
                mindeg = vDegree[i];
                startvertex = i;
            }
        }
        DFSUtil(startvertex, visited, vDegree, k);
 
        // DFS traversal to update degrees of all
        // vertices.
        for(int i = 0; i < V; i++)
            if (!visited[i])
                DFSUtil(i, visited, vDegree, k);
 
        // PRINTING K CORES
        Console.WriteLine("K-Cores : ");
         
        for(int v = 0; v < V; v++)
        {
             
            // Only considering those vertices
            // which have degree >= K after BFS
            if (vDegree[v] >= k)
            {
                Console.Write("\n " + v);
 
                // Traverse adjacency list of v
                // and print only those adjacent
                // which have vDegree >= k after
                // BFS.
                foreach(int i in adj[v])
                    if (vDegree[i] >= k)
                        Console.Write(" -> " + i);
            }
        }
    }
}
 
// Driver Code
public static void Main(String[] args)
{
     
    // Create a graph given in the
    // above diagram
    int k = 3;
     
    Graph g1 = new Graph(9);
    g1.addEdge(0, 1);
    g1.addEdge(0, 2);
    g1.addEdge(1, 2);
    g1.addEdge(1, 5);
    g1.addEdge(2, 3);
    g1.addEdge(2, 4);
    g1.addEdge(2, 5);
    g1.addEdge(2, 6);
    g1.addEdge(3, 4);
    g1.addEdge(3, 6);
    g1.addEdge(3, 7);
    g1.addEdge(4, 6);
    g1.addEdge(4, 7);
    g1.addEdge(5, 6);
    g1.addEdge(5, 8);
    g1.addEdge(6, 7);
    g1.addEdge(6, 8);
    g1.printKCores(k);
 
    Console.WriteLine();
 
    Graph g2 = new Graph(13);
    g2.addEdge(0, 1);
    g2.addEdge(0, 2);
    g2.addEdge(0, 3);
    g2.addEdge(1, 4);
    g2.addEdge(1, 5);
    g2.addEdge(1, 6);
    g2.addEdge(2, 7);
    g2.addEdge(2, 8);
    g2.addEdge(2, 9);
    g2.addEdge(3, 10);
    g2.addEdge(3, 11);
    g2.addEdge(3, 12);
     
    g2.printKCores(k);
}
}
 
// This code is contributed by Princi Singh


输出 :

K-Cores : 

[2] -> 3 -> 4 -> 6
[3] -> 2 -> 4 -> 6 -> 7
[4] -> 2 -> 3 -> 6 -> 7
[6] -> 2 -> 3 -> 4 -> 7
[7] -> 3 -> 4 -> 6

K-Cores : 

上述解决方案的时间复杂度为 O(V + E),其中 V 是顶点数,E 是边数。

相关概念:
简并度:图的简并度是最大值 k 使得图具有 k 核。例如,上面显示的图表有 3 个核心,但没有 4 个或更高的核心。因此,上图是 3 退化的。
图的退化用于衡量图的稀疏程度。