图的割点(边表集实现)
? ? Name: 圖的割點(邊表集實現)
? ? Copyright:?
? ? Author: 巧若拙?
? ? Date: 20-11-14 21:17
? ? Description:?
? ? 在一個無向連通圖中。假設有一個頂點集合,刪除這個頂點集合。以及這個集合中全部頂點相關聯的邊以后,原圖變成多個連通塊,就稱這個點集為割點集合。
求割點與橋的算法是R.Tarjan發明的。對圖深度優先搜索。定義DFS(u)為u在搜索樹(下面簡稱為樹)中被遍歷到的次序號(等價于時間戳)。
定義Low(u)為u或u的子樹中能通過非父子邊追溯到的最早的節點。即DFS序號最小的節點的序號。
依據定義,則有: ?
Low(u)=Min { DFS(u) ,DFS(v)},當中 (u,v)為后向邊(返祖邊) 等價于 DFS(v)<DFS(u)且v不為u的父親節點 Low(v) (u,v)為樹枝邊(父子邊)?
一個頂點u是割點。當且僅當滿足(1)或(2) :
(1) u為樹根。且u有多于一個子樹。?
(2) u不為樹根。且滿足存在(u,v)為樹枝邊(或稱父子邊,即u為v在搜索樹中的父親),使得DFS(u)<=Low(v)。
本文用邊表集存儲圖的信息,實現了遞歸和非遞歸兩種算法。
?
*/
#include<stdio.h>
#include<stdlib.h>
#define MAXN 26 ? //最大變量(頂點)數量?
#define MAXM 100000 ? //最大關系式數量?
typedef char VertexType; //頂點類型由用戶自己定義
typedef int EdgeType; //邊上的權值類型由用戶自己定義
typedef struct Edge{ //邊集數組?
? ? int u, v; //弧尾和弧頭?
? ? int next; //指向同一個弧尾的下一條邊?
// ? ?EdgeType weight; //權值,對于非網圖能夠不須要?
} EdgeLib;
EdgeLib edge[MAXM]; //存儲邊信息
int first[MAXN]; //指向頂點的第一條邊
int flag[MAXN] = {0}; //存儲頂點是否為割點?
int num[MAXN] = {0}; //存儲頂點的時間戳信息?
int low[MAXN] = {0}; //存儲頂點的最小時間戳信息?
int index = 0; //用來進行時間戳的遞增?
void CreateGraph(int n, int m);//創建一個圖
void PrintGraph(int n, int m);//輸出圖
void CutPoint_DFS(int root, int cur, int father);//採用深度優先搜索尋找割點(遞歸算法)?
void CutPoint(int root, int n);//採用深度優先搜索尋找割點(非遞歸算法)?
int main()
{
? ? int i, m, n;
? ??
? ? printf("請輸入頂點數量和邊數量:\n");?
? ? scanf("%d%d", &n, &m); ? ?
? ??
? ? CreateGraph(n, m);//創建一個圖
? ? PrintGraph(n, m);//輸出圖
? ??
?// ? CutPoint_DFS(0, 0, 0);//從0號頂點開始深度優先搜索尋找割點(遞歸算法)?
? ? CutPoint(0, n);?
? ? printf("\n割點為:");?
? ? for (i=0; i<n; i++)//輸出全部割點
? ? {
? ? ? ? if (flag[i] == 1)
? ? ? ? ? ? printf("%d ", i);
? ? }?
? ? printf("\n");
? ??
? ? return 0;
}
void CreateGraph(int n, int m)//創建一個圖
{
? ? int i;
? ??
? ? for (i=0; i<n; i++)//初始化圖?
? ? {
? ? ? ? first[i] = -1;
? ? ? ? num[i] = low[i] = flag[i] = 0;
? ? }
? ??
? ? for (i=0; i<m+m; i+=2) ?//讀入邊信息(注意是無向圖)?
? ? {
? ? ? ? scanf("%d%d", &edge[i].u, &edge[i].v);
? ? ? ? edge[i].next = first[edge[i].u];
? ? ? ? first[edge[i].u] = i;
? ? ? ??
? ? ? ? edge[i+1].u = edge[i].v;
? ? ? ? edge[i+1].v = edge[i].u;
? ? ? ? edge[i+1].next = first[edge[i+1].u];
? ? ? ? first[edge[i+1].u] = i + 1;
? ? }
}?
void PrintGraph(int n, int m)//輸出圖
{
? ? int i, j;
? ??
? ? for (i=0; i<n; i++)
? ? {
? ? ? ? printf("%d: ", i);
? ? ? ? j = first[i]; //指向i的第一條邊?
? ? ? ? while (j != -1)
? ? ? ? {
? ? ? ? ? ? printf("<%d, %d>, ", edge[j].u, edge[j].v);
? ? ? ? ? ? j = edge[j].next; //指向下一條邊?
? ? ? ? }
? ? ? ? printf("\n");
? ? }
? ? printf("\n");
}?
void CutPoint_DFS(int root, int cur, int father)//採用深度優先搜索尋找割點(遞歸算法)?
{
? ? int k, child = 0;
? ??
? ? num[cur] = low[cur] = ++index;
? ? k = first[cur];
? ? while (k != -1)
? ? {
? ? ? ? if (num[edge[k].v] == 0) //新結點做兒子
? ? ? ? {
? ? ? ? ? ? child++;
? ? ? ? ? ? CutPoint_DFS(root, edge[k].v, cur);
? ? ? ? ? ??
? ? ? ? ? ? low[cur] = (low[cur] < low[edge[k].v]) ? low[cur] : low[edge[k].v];//取最小值?
? ? ? ? ? ??
? ? ? ? ? ? if ((cur != root && num[cur] <= low[edge[k].v])
? ? ? ? ? ? ?|| (cur == root && child == 2))
? ? ? ? ? ? {
? ? ? ? ? ? ? ? flag[cur] = 1;
? ? ? ? ? ? }
? ? ? ? }?
? ? ? ? else if (edge[k].v != father) //與旁系祖先有連接,事實上也能夠不加這個限制條件,由于假設父親是自己則low[cur]值不變?
? ? ? ? {
? ? ? ? ? ? low[cur] = (low[cur] < num[edge[k].v]) ?
low[cur] : num[edge[k].v];//取最小值?
? ? ? ? }?
? ? ? ??
? ? ? ? k = edge[k].next;
? ? }
}
void CutPoint(int root, int n)//採用深度優先搜索尋找割點(非遞歸算法)?
{
? ? int Stack[MAXN]; //用來存儲當前被處理頂點的棧?
? ? int SF[MAXN]; //指向頂點的第一條未搜索邊
? ? int child[MAXN] = {0}; //存儲頂點的兒子數量?
? ? int k, u, v, top = 0;
? ??
? ? for (u=0; u<n; u++)//初始化SF?
? ? ? ? SF[u] = first[u];
? ? ? ??
? ? Stack[top] = root;
? ? num[root] = low[root] = ++index;
? ? while (top >= 0)
? ? {
? ? ? ? k = SF[Stack[top]];
? ? ? ? if (k != -1)
? ? ? ? {
? ? ? ? SF[Stack[top]] = edge[k].next; //指向下一條邊?
? ? ? ? ? ? if (num[edge[k].v] == 0)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? child[Stack[top]]++;
? ? ? ? ? ? ? ? Stack[++top] = edge[k].v;
? ? ? ? ? ? ? ? low[edge[k].v] = num[edge[k].v] = ++index;
? ? ? ? ? ? }
? ? ? ? ? ? else
? ? ? ? ? ? {
? ? ? ? ? ? ? ? low[Stack[top]] = (low[Stack[top]] < num[edge[k].v]) ? low[Stack[top]] : num[edge[k].v];//取最小值
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? else
? ? ? ? {
? ? ? ? ? ? if (top > 0)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? u = Stack[top-1];
? ? ? ? ? ? ? ? v = Stack[top];
? ? ? ? ? ? ? ? low[u] = (low[u] < low[v]) ? low[u] : low[v];
? ? ? ? ? ? ? ? if ((u != root && low[v] >= num[u])
? ? ? ? ? ? ? ? ?|| (u == root && child[u] == 2))
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? flag[u] = 1;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? top--;
? ? ? ? }
? ? } ? ? ? ?
}
總結
以上是生活随笔為你收集整理的图的割点(边表集实现)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MapReduce中的partition
- 下一篇: selenium + python自动化