最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C#圖表算法之有向圖

 更新時(shí)間:2022年04月24日 16:49:12   作者:Ruby_Lu  
這篇文章介紹了C#圖表算法之有向圖,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

在有向圖中,邊是單向的:每條邊連接的兩個(gè)頂點(diǎn)都是一個(gè)有序?qū)?,它們的鄰接性是單向的。許多應(yīng)用都是天然的有向圖,如下圖。為實(shí)現(xiàn)添加這種單向性的限制很容易也很自然,看起來(lái)沒(méi)什么壞處。但實(shí)際上這種組合性的結(jié)構(gòu)對(duì)算法有深刻的影響,使得有向圖和無(wú)向圖的處理大有不同。

1.術(shù)語(yǔ)

雖然我們?yōu)橛邢驁D的定義和無(wú)向圖幾乎相同(將使用的部分算法和代碼也是),但為了說(shuō)明邊的方向性而產(chǎn)生的細(xì)小文字差異所代表的結(jié)構(gòu)特性是重點(diǎn)。

定義:一幅有方向性的圖(或有向圖)是由一組頂點(diǎn)和一組有方向的邊組成的,每條有方向的邊都連著有序的一對(duì)頂點(diǎn)。

我們稱一條有向邊由第一個(gè)頂點(diǎn)指出并指向第二個(gè)頂點(diǎn)。在一幅有向圖中,一個(gè)頂點(diǎn)的出度為由該頂點(diǎn)指出的邊的總數(shù);一個(gè)頂點(diǎn)的入度為指向該頂點(diǎn)的邊的總數(shù)。一條有向邊的第一個(gè)頂點(diǎn)稱為它的頭,第二個(gè)頂點(diǎn)則稱為它的尾。用 v->w 表示有向圖中一條由v 指向 w 的邊。一幅有向圖的兩個(gè)頂點(diǎn)的關(guān)系可能有四種:沒(méi)有邊相連;v->w; w-> v;v->w 和 w->v。

在一幅有向圖中,有向路徑由一系列頂點(diǎn)組成,對(duì)于其中的每個(gè)頂點(diǎn)都存在一條有向邊從它指向序列中的下一個(gè)頂點(diǎn)。有向環(huán)為一條至少含有一條邊且起點(diǎn)和終點(diǎn)相同的有向路徑。路徑或環(huán)的長(zhǎng)度即為其中所包含的邊數(shù)。

當(dāng)存在從 v 到 w 的有向路徑時(shí),稱頂點(diǎn) w 能夠由頂點(diǎn) v 達(dá)到。我們需要理解有向圖中的可達(dá)性和無(wú)向圖中的連通性的區(qū)別。

2.有向圖的數(shù)據(jù)類型

有向圖API

有向圖表示

我們使用鄰接表來(lái)表示有向圖,其中邊 v -> w 表示頂點(diǎn) v 所對(duì)應(yīng)的鄰接鏈表中包含一個(gè) w 頂點(diǎn)。這種表示方法和無(wú)向圖幾乎相同而且更明晰,因?yàn)槊織l邊都只會(huì)出現(xiàn)一次。

有向圖取反

Digraph 的 API 中還添加了一個(gè) Reverse 方法。它返回該有向圖的一個(gè)副本,但將其中所有邊的方向反轉(zhuǎn)。在處理有向圖時(shí)這個(gè)方法有時(shí)很有用,因?yàn)檫@樣用例就可以找出“指向”每個(gè)頂點(diǎn)的所有邊,而 Adj 方法給出的是由每個(gè)頂點(diǎn)指出的邊所連接的所有頂點(diǎn)。

頂點(diǎn)的符號(hào)名

在有向圖中,使用符號(hào)名作為頂點(diǎn)也很簡(jiǎn)單,參考SymbolGraph。

namespace Digraphs
{
    public class Digraph
    {
        private int v;
        private int e;
        private List<int>[] adj;

        public Digraph(int V)
        {
            this.v = V;
            this.e = 0;
            adj = new List<int>[v];
            for (var i = 0; i < v; i++)
            {
                adj[i] = new List<int>();
            }
        }

        public int V()
        {
            return v;
        }

        public int E()
        {
            return e;
        }

        public List<int> Adj(int v)
        {
            return adj[v];
        }

        public void AddEdge(int v, int w)
        {
            adj[v].Add(w);
            e++;
        }

        public Digraph Reverse()
        {
            Digraph R = new Digraph(v);
            for (var i = 0; i < v; i++)
                foreach (var w in Adj(i))
                    R.AddEdge(w,i);

            return R;
        }
    }
}

3.有向圖的可達(dá)性

在無(wú)向圖中介紹的深度優(yōu)先搜索DepthFirstSearch ,解決了單點(diǎn)連通性的問(wèn)題,使得用例可以判定其他頂點(diǎn)和給定的起點(diǎn)是否連通。使用完全相同的代碼,將其中的 Graph 替換成 Digraph 也可以解決有向圖中的單點(diǎn)可達(dá)性問(wèn)題(給定一幅有向圖和一個(gè)起點(diǎn) s ,是否存在一條從 s 到達(dá)給定頂點(diǎn) v 的有向路徑?)。

在添加了一個(gè)接受多個(gè)頂點(diǎn)的構(gòu)造函數(shù)之后,這份 API 使得用例能夠解決一個(gè)更加一般的問(wèn)題 -- 多點(diǎn)可達(dá)性 (給定一幅有向圖和頂點(diǎn)的集合,是否存在一條從集合中的任意頂點(diǎn)到達(dá)給定頂點(diǎn) v 的有向路徑?)

下面的DirectedDFS 算法使用了解決圖處理的標(biāo)準(zhǔn)范例和標(biāo)準(zhǔn)的深度優(yōu)先搜索來(lái)解決。對(duì)每個(gè)起點(diǎn)調(diào)用遞歸方法 Dfs ,以標(biāo)記遇到的任意頂點(diǎn)。

namespace Digraphs
{
    public class DirectedDFS
    {
        private bool[] marked;

        public DirectedDFS(Digraph G, int s)
        {
            marked = new bool[G.V()];
            Dfs(G,s);
        }

        public DirectedDFS(Digraph G, IEnumerable<int> sources)
        {
            marked = new bool[G.V()];
            foreach (var s in sources)
            {
                if (!marked[s])
                    Dfs(G,s);
            }
        }

        private void Dfs(Digraph G, int V)
        {
            marked[V] = true;
            foreach (var w in G.Adj(V))
            {
                if (!marked[w])
                    Dfs(G,w);
            }
        }

        public bool Marked(int v)
        {
            return marked[v];
        }
    }
}

在有向圖中,深度優(yōu)先搜索標(biāo)記由一個(gè)集合的頂點(diǎn)可達(dá)的所有頂點(diǎn)所需的時(shí)間與被標(biāo)記的所有頂點(diǎn)的出度之和成正比。

有向圖的尋路

在無(wú)向圖中的尋找路徑的算法,只需將 Graph 替換為 Digraph 就能夠解決下面問(wèn)題:

  • 1.單點(diǎn)有向路徑:給定一幅有向圖和一個(gè)起點(diǎn) s ,從 s 到給定目的頂點(diǎn)是否存在一條有向路徑?如果有,找出這條路徑。
  • 2.單點(diǎn)最短有向路徑:給定一幅有向圖和一個(gè)起點(diǎn) s ,從 s 到給定目的頂點(diǎn) v 是否存在一條有向路徑?如果有,找出其中最短的那條(所含邊數(shù)最少)。

4.環(huán)和有向無(wú)環(huán)圖

在和有向圖相關(guān)的實(shí)際應(yīng)用中,有向環(huán)特別的重要。沒(méi)有計(jì)算機(jī)的幫助,在一幅普通的有向圖中找出有向環(huán)可能會(huì)很困難。從原則上來(lái)說(shuō),一幅有向圖可能含有大量的環(huán);在實(shí)際應(yīng)用中,我們一般只重點(diǎn)關(guān)注其中一小部分,或者只想知道它們是否存在。

調(diào)度問(wèn)題

一種應(yīng)用廣泛的模型是給定一組任務(wù)并安排它們的執(zhí)行順序,限制條件是這些任務(wù)的執(zhí)行方法和開(kāi)始時(shí)間。限制條件還可能包括任務(wù)的耗時(shí)以及消耗的資源。最重要的一種限制條件叫做優(yōu)先級(jí)限制,它指明了哪些任務(wù)必須在哪些任務(wù)之前完成。不同類型的限制條件會(huì)產(chǎn)生不同類型不同難度的調(diào)度問(wèn)題。

下面以一個(gè)正在安排課程的大學(xué)生為例,有些課程是其他課程的先導(dǎo)課程:

如果假設(shè)該學(xué)生一次只能修一門(mén)課程,就會(huì)遇到優(yōu)先級(jí)下的調(diào)度問(wèn)題:給定一組需要完成的任務(wù),以及一組關(guān)于任務(wù)完成的先后次序的優(yōu)先級(jí)限制。在滿足限制條件的前提下應(yīng)該如何安排并完成所有任務(wù)?

對(duì)于任意一個(gè)這樣的問(wèn)題,我們先畫(huà)出一幅有向圖,其中頂點(diǎn)對(duì)應(yīng)任務(wù),有向邊對(duì)應(yīng)優(yōu)先級(jí)順序。為了簡(jiǎn)化問(wèn)題,我們以整數(shù)為頂點(diǎn):

在有向圖中,優(yōu)先級(jí)限制下的調(diào)度問(wèn)題等價(jià)于一個(gè)基本問(wèn)題--拓?fù)渑判?/strong>:給定一幅圖,將所有頂點(diǎn)排序,使得所有的有向邊均從排在前面的元素指向排在后面的元素(或者說(shuō)明無(wú)法做到這一點(diǎn))。

如圖,所有的邊都是向下的,所以清晰地表示了這幅有向圖模型所代表的有優(yōu)先級(jí)限制的調(diào)度問(wèn)題的一個(gè)解決方法:按照這個(gè)順序,該同學(xué)可以滿足先導(dǎo)課程限制的條件下修完所有課程。

有向圖中的環(huán)

如果任務(wù) x 必須在任務(wù) y 之前完成,而任務(wù) y 必須在任務(wù) z 之前完成,但任務(wù) z 又必須在任務(wù) x 之前完成,那肯定是有人搞錯(cuò)了,因?yàn)檫@三個(gè)限制條件是不可能被同時(shí)滿足的。一般來(lái)說(shuō),如果一個(gè)優(yōu)先級(jí)限制的問(wèn)題中存在有向環(huán),那么這個(gè)問(wèn)題肯定是無(wú)解的。要檢查這種錯(cuò)誤,需要解決 有向環(huán)檢測(cè):給定的有向圖中包含有向環(huán)嗎?如果有,按照路徑的方向從某個(gè)頂點(diǎn)并返回自己來(lái)找到環(huán)上的所有頂點(diǎn)。

一幅有向圖中含有環(huán)的數(shù)量可能是圖的大小的指數(shù)級(jí)別,因此我們只需找到一個(gè)環(huán)即可,而不是所有環(huán)。在任務(wù)調(diào)度和其他許多實(shí)際問(wèn)題中不允許出現(xiàn)有向環(huán),因此有向無(wú)環(huán)圖就變得很特殊。

基于深度優(yōu)先搜索可以解決有向環(huán)檢測(cè)的問(wèn)題,因?yàn)橛上到y(tǒng)維護(hù)的遞歸調(diào)用的棧表示的正是“當(dāng)前”正在遍歷的有向路徑。一旦我們找到了一條有向邊 v -> w 且 w 已經(jīng)存在于棧中,就找到了一個(gè)環(huán),因?yàn)闂1硎镜氖且粭l由 w 到 v 的有向路徑,而 v -> w 正好補(bǔ)全了這個(gè)環(huán)。如果沒(méi)有找到這樣的邊,就意味著這副有向圖是無(wú)環(huán)的。DirectedCycle 基于這個(gè)思想實(shí)現(xiàn)的:

namespace Digraphs
{
    public class DirectedCycle
    {
        private bool[] marked;
        private int[] edgeTo;
        private Stack<int> cycle;//有向環(huán)中的所有頂點(diǎn)(如果存在)
        private bool[] onStack;//遞歸調(diào)用的棧上的所有頂點(diǎn)

        public DirectedCycle(Digraph G)
        {
            onStack = new bool[G.V()];
            edgeTo = new int[G.V()];
            marked = new bool[G.V()];

            for (int v = 0; v < G.V(); v++)
            {
                if (!marked[v])
                    Dfs(G,v);
            }
        }

        private void Dfs(Digraph G, int v)
        {
            onStack[v] = true;
            marked[v] = true;
            foreach (var w in G.Adj(v))
            {
                if (hasCycle())
                    return;
                else if (!marked[w])
                {
                    edgeTo[w] = v;
                    Dfs(G, w);
                }
                else if (onStack[w])
                {
                    cycle = new Stack<int>();
                    for (int x = v; x != w; x = edgeTo[x])
                        cycle.Push(x);
                    cycle.Push(w);
                    cycle.Push(v);
                }
            }
            onStack[v] = false;
        }

        private bool hasCycle()
        {
            return cycle != null;
        }

        public IEnumerable<int> Cycle()
        {
            return cycle;
        }
    }
}

該類為標(biāo)準(zhǔn)的的遞歸 Dfs 方法添加了一個(gè)布爾類型的數(shù)組 onStack 來(lái)保存遞歸調(diào)用期間棧上的所有頂點(diǎn)。當(dāng)它找到一條邊 v -> w 且 w 在棧中時(shí),它就找到了一個(gè)有向環(huán)。環(huán)上的所有頂點(diǎn)可以通過(guò) edgeTo 中的鏈接得到。

在執(zhí)行 Dfs 時(shí),查找的是一條由起點(diǎn)到 v 的有向路徑。要保存這條路徑,DirectedCycle 維護(hù)了一個(gè)由頂點(diǎn)索引的數(shù)組onStack,以標(biāo)記遞歸調(diào)用的棧上的所有頂點(diǎn)(在調(diào)用 Dfs 時(shí)將 onStack[ v ] 設(shè)為 true,在調(diào)用結(jié)束時(shí)將其設(shè)為 false)。DirectedCycle 同時(shí)也使用了一個(gè)edgeTo 數(shù)組,在找到有向環(huán)時(shí)返回環(huán)中的所有頂點(diǎn)。

頂點(diǎn)的深度優(yōu)先次序與拓?fù)渑判?/h3>

優(yōu)先級(jí)限制下的調(diào)度問(wèn)題等價(jià)于計(jì)算有向無(wú)環(huán)圖中的所有頂點(diǎn)的拓?fù)渑判颍?/p>

下面算法的基本思想是深度優(yōu)先搜索正好只會(huì)訪問(wèn)每個(gè)頂點(diǎn)一次。如果將 Dfs 的參數(shù)頂點(diǎn)保存在一個(gè)數(shù)據(jù)結(jié)構(gòu)中,遍歷這個(gè)數(shù)據(jù)結(jié)構(gòu)實(shí)際上就能訪問(wèn)圖中的所有頂點(diǎn),遍歷的順序取決于這個(gè)數(shù)據(jù)結(jié)構(gòu)的性質(zhì)以及是在遞歸調(diào)用之前還是之后進(jìn)行保存。在典型的應(yīng)用中,頂點(diǎn)一下三種排列順序:

  • 前序:在遞歸調(diào)用之前將頂點(diǎn)加入隊(duì)列;
  • 后序:在遞歸調(diào)用之后將頂點(diǎn)加入隊(duì)列;
  • 逆后序:在遞歸調(diào)用之后將頂點(diǎn)壓入棧。

該類允許用例用各種順序遍歷深度優(yōu)先搜索經(jīng)過(guò)得頂點(diǎn)。這在高級(jí)得有向圖處理算法非常有用,因?yàn)樗阉鞯眠f歸性使得我們能夠證明這段計(jì)算得許多性質(zhì)。

namespace Digraphs
{
    public class DepthFirstOrder
    {
        private bool[] marked;
        private Queue<int> pre;//所有頂點(diǎn)的前序排列
        private Queue<int> post;//所有頂點(diǎn)的后序排列
        private Stack<int> reversePost;//所有頂點(diǎn)的逆后序排列

        public DepthFirstOrder(Digraph G)
        {
            marked = new bool[G.V()];
            pre = new Queue<int>();
            post = new Queue<int>();
            reversePost = new Stack<int>();

            for (var v = 0; v < G.V(); v++)
            {
                if (!marked[v])
                    Dfs(G,v);
            }
        }

        private void Dfs(Digraph G, int v)
        {
            pre.Enqueue(v);

            marked[v] = true;
            foreach (var w in G.Adj(v))
            {
                if (!marked[w])
                    Dfs(G,w);
            }

            post.Enqueue(v);
            reversePost.Push(v);
        }

        public IEnumerable<int> Pre()
        {
            return pre;
        }

        public IEnumerable<int> Post()
        {
            return post;
        }

        public IEnumerable<int> ReversePost()
        {
            return reversePost;
        }
    }
}

一幅有向無(wú)環(huán)圖得拓?fù)渑判蚣礊樗许旤c(diǎn)的逆后序排列。

拓?fù)渑判?/h3>
namespace Digraphs
{
    public class Topological
    {
        private IEnumerable<int> order;
        public Topological(Digraph G)
        {
            DirectedCycle cycleFinder = new DirectedCycle(G);
            if (cycleFinder.HasCycle())
            {
                DepthFirstOrder dfs = new DepthFirstOrder(G);
                order = dfs.ReversePost();
            }
        }

        public IEnumerable<int> Order()
        {
            return order;
        }

        public bool IsDAG()
        {
            return order != null;
        }
    }
}

這段使用DirectedCycle 檢測(cè)是否有環(huán),使用DepthFirstOrder 返回有向圖的逆后序。

使用深度優(yōu)先搜索對(duì)有向無(wú)環(huán)圖進(jìn)行拓?fù)渑判蛩璧臅r(shí)間和 V+E 成正比。第一遍深度優(yōu)先搜索保證了不存在有向環(huán),第二遍深度優(yōu)先搜索產(chǎn)生了頂點(diǎn)的逆后序排列。

在實(shí)際應(yīng)用中,拓?fù)渑判蚝陀邢颦h(huán)的檢測(cè)總是一起出現(xiàn),因?yàn)橛邢颦h(huán)的檢測(cè)是排序的前提。例如,在一個(gè)任務(wù)調(diào)度應(yīng)用中,無(wú)論計(jì)劃如何安排,其背后的有向圖中包含的環(huán)意味著存在一個(gè)必須被糾正的嚴(yán)重錯(cuò)誤。因此,解決任務(wù)調(diào)度類應(yīng)用通常需要一下3步:

  • 1.指明任務(wù)和優(yōu)先級(jí)條件;
  • 2.不斷檢測(cè)并去除有向圖中的所有環(huán),以確保存在可行方案;
  • 3.使用拓?fù)渑判蚪鉀Q調(diào)度問(wèn)題。

類似地,調(diào)度方案的任何變動(dòng)之后都需要再次檢查是否存在環(huán),然后再計(jì)算新的調(diào)度安排。

5.有向圖中的強(qiáng)連通性

如果兩個(gè)頂點(diǎn) v 和 w 是相互可達(dá)的,則稱它們?yōu)閺?qiáng)連通的。也就是說(shuō),即存在一條從 v 到 w 的有向路徑,也存在一條從 w 到 v 的有向路徑。如果一幅有向圖中的任意兩個(gè)頂點(diǎn)都是強(qiáng)連通的,則稱這副有向圖也是強(qiáng)連通的。

下面是強(qiáng)連通圖的例子,可以看到,環(huán)在強(qiáng)連通性的理解上起著重要的作用。

強(qiáng)連通分量

和無(wú)向圖中的連通性一樣,有向圖中的強(qiáng)連通性也是一種頂點(diǎn)之間的等價(jià)關(guān)系:

  • 自反性:任意頂點(diǎn) v 和自己都是強(qiáng)連通的。
  • 對(duì)稱性:如果 v 和 w 是強(qiáng)連通的,那么 w 和 v 也是。
  • 傳遞性:如果 v 和 w 是強(qiáng)連通的且 w 和 x 也是強(qiáng)連通的,那么 v 和 x 也是強(qiáng)連通的。

作為一種等價(jià)關(guān)系,強(qiáng)連通性將所有頂點(diǎn)分為了一些等價(jià)類,每個(gè)等價(jià)類都是由相互均為強(qiáng)連通的頂點(diǎn)的最大子集組成。我們稱這些子集為強(qiáng)連通分量。如下圖,一個(gè)含有 V 個(gè)頂點(diǎn)的有向圖含有 1~ V個(gè)強(qiáng)連通分量——一個(gè)強(qiáng)連通圖只含有一個(gè)強(qiáng)連通分量,而一個(gè)有向無(wú)環(huán)圖則含有 V 個(gè)強(qiáng)連通分量。需要注意的是強(qiáng)連通分量的定義是基于頂點(diǎn)的,而不是邊。有些邊連接的兩個(gè)頂點(diǎn)都在同一個(gè)強(qiáng)連通分量中,而有些邊連接的兩個(gè)頂點(diǎn)則不在同一強(qiáng)連通分量中。

強(qiáng)連通分量API

設(shè)計(jì)一種平方級(jí)別的算法來(lái)計(jì)算強(qiáng)連通分量并不困難,單對(duì)于處理實(shí)際應(yīng)用中的大型圖來(lái)說(shuō),平方級(jí)別的時(shí)間和空間需求是不可接受的。

Kosaraju算法

在有向圖中如何高效地計(jì)算強(qiáng)連通分量?我們只需修改無(wú)向圖連通分量的算法 CC,KosarajuCC 算法如下,它將會(huì)完成一下任務(wù):

1.在給定的一幅有向圖 G 中,使用 DepthFirstOrder 來(lái)計(jì)算它的反向圖 GR 的逆后序排列;

2.在 G 中進(jìn)行標(biāo)準(zhǔn)的深度優(yōu)先搜索,但是要按照剛才計(jì)算得到的順序而非標(biāo)準(zhǔn)的順序來(lái)訪問(wèn)所有未被標(biāo)記的頂點(diǎn);

3.在構(gòu)造函數(shù)中,所有在同一個(gè)遞歸 Dfs() 調(diào)用中被訪問(wèn)到的頂點(diǎn)都在同一個(gè)強(qiáng)連通分量中,將它們按照和 CC 相同的方式識(shí)別出來(lái)。

namespace Digraphs
{
    public class KosarajuCC
    {
        private bool[] marked;//已訪問(wèn)的頂點(diǎn)
        private int[] id;//強(qiáng)連通分量的標(biāo)識(shí)符
        private int count;//強(qiáng)連通分量的數(shù)量

        public KosarajuCC(Digraph G)
        {
            marked = new bool[G.V()];
            id = new int[G.V()];
            DepthFirstOrder order = new DepthFirstOrder(G.Reverse());
            foreach (var s in order.ReversePost())
            {
                if (!marked[s])
                {
                    Dfs(G,s);
                    count++;
                }
            }
        }

        private void Dfs(Digraph G, int v)
        {
            marked[v] = true;
            id[v] = count;
            foreach (var w in G.Adj(v))
            {
                if (!marked[w])
                    Dfs(G,w);
            }
        }

        public bool StronglyConnected(int v, int w)
        {
            return id[v] == id[w];
        }

        public int Id(int v)
        {
            return id[v];
        }

        public int Count()
        {
            return count;
        }
    }
}

Kosaraju 算法的預(yù)處理所需的時(shí)間和空間與 V+E 成正比且支持常數(shù)時(shí)間的有向圖強(qiáng)連通性的查詢。

再談可達(dá)性

在無(wú)向圖中如果兩個(gè)頂點(diǎn) V 和 W 是連通的,那么就既存在一條從 v 到 w 的路徑也存在一條從 w 到 v 的路徑。在有向圖中如果兩個(gè)頂點(diǎn) v 和 w 是強(qiáng)連通的,那么就既存在一條從 v 到 w 的路徑也存在另一條從 w 到 v 的路徑。但對(duì)于一對(duì)非強(qiáng)連通的頂點(diǎn),也許存在一條從 v 到 w 的路徑,也許存在一條從 w 到 v 的路徑,也許兩條都不存在,但不可能兩條都存在。

頂點(diǎn)對(duì)的可達(dá)性:對(duì)于無(wú)向圖,等價(jià)于連通性問(wèn)題;對(duì)于有向圖,它和強(qiáng)連通性有很大區(qū)別。 CC 實(shí)現(xiàn)需要線性級(jí)別的預(yù)處理時(shí)間才能支持常數(shù)時(shí)間的操作。在有向圖的相應(yīng)實(shí)現(xiàn)中能否達(dá)到這樣的性能?

有向圖 G 的傳遞閉包是由相同的一組頂點(diǎn)組成的另一幅有向圖,在傳遞閉包中存在一條從 v 指向 w 的邊當(dāng)且僅當(dāng)在 G 中 w 是從 v 可達(dá)的。

根據(jù)約定,每個(gè)頂點(diǎn)對(duì)于自己都是可達(dá)的,因此傳遞閉包會(huì)含有 V 個(gè)自環(huán)。上圖只有 22 條有向邊,但它的傳遞閉包含有可能的 169 條有向邊中的 102 條。一般來(lái)說(shuō),一幅有向圖的傳遞閉包中所含的邊都比原圖中多得多。例如,含有 V 個(gè)頂點(diǎn)和 V 條邊的有向環(huán)的傳遞閉包是一幅含有 V 的平方條邊的有向完全圖。因?yàn)閭鬟f閉包一般都是稠密的,我們通常都將它們表示為一個(gè)布爾值矩陣,其中 v 行 w 列的值為 true 當(dāng)且僅當(dāng) w 是從 v 可達(dá)的。與其計(jì)算一幅有向圖的傳遞閉包,不如使用深度優(yōu)先搜索來(lái)實(shí)現(xiàn)如下API:

下面的算法使用DirectedDFS 實(shí)現(xiàn):

namespace Digraphs
{
    public class TransitiveClosure
    {
        private DirectedDFS[] all;

        public TransitiveClosure(Digraph G)
        {
            all = new DirectedDFS[G.V()];
            for (var v = 0; v < G.V(); v++)
                all[v] = new DirectedDFS(G,v);
        }

        public bool Reachable(int v, int w)
        {
            return all[v].Marked(w);
        }
    }
}

該算法無(wú)論對(duì)于稀疏圖還是稠密圖,都是理想解決方案,但對(duì)于大型有向圖不適用,因?yàn)闃?gòu)造函數(shù)所需的空間和 V 的平方成正比,所需的時(shí)間和 V(V+ E) 成正比。

總結(jié)

到此這篇關(guān)于C#圖表算法之有向圖的文章就介紹到這了。希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 新手必看Unity2019 2020保姆級(jí)安裝教程

    新手必看Unity2019 2020保姆級(jí)安裝教程

    這篇文章主要介紹了Unity2019 2020安裝教程,本文分步驟通過(guò)圖文并茂的形式給大家介紹Unity2019 2020安裝方法,需要的朋友可以參考下
    2021-05-05
  • C#書(shū)寫(xiě)規(guī)范

    C#書(shū)寫(xiě)規(guī)范

    C#書(shū)寫(xiě)規(guī)范...
    2007-03-03
  • 使用VS2019生成C#應(yīng)用安裝包的方法步驟

    使用VS2019生成C#應(yīng)用安裝包的方法步驟

    本文主要介紹了使用VS2019生成C#應(yīng)用安裝包的方法步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-05-05
  • 淺談Unity中的Shader

    淺談Unity中的Shader

    Shader,中文名為著色器,對(duì)很多開(kāi)發(fā)者來(lái)說(shuō)它是一個(gè)神秘的存在。Shader其實(shí)就是專門(mén)用來(lái)渲染圖形的一種技術(shù),通過(guò)shader,我們可以自定義顯卡渲染畫(huà)面的算法,使畫(huà)面達(dá)到我們想要的效果
    2021-06-06
  • C#實(shí)現(xiàn)Nginx平滑加權(quán)輪詢算法

    C#實(shí)現(xiàn)Nginx平滑加權(quán)輪詢算法

    這篇文章主要為大家詳細(xì)介紹了C#實(shí)現(xiàn)Nginx平滑加權(quán)輪詢算法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-07-07
  • C#計(jì)算兩個(gè)文件的相對(duì)目錄算法的實(shí)例代碼

    C#計(jì)算兩個(gè)文件的相對(duì)目錄算法的實(shí)例代碼

    現(xiàn)在已知兩個(gè)文件相對(duì)于網(wǎng)站根目錄的路徑,如何計(jì)算相對(duì)路徑呢,有需要的朋友可以參考一下
    2013-09-09
  • C#流程控制詳解

    C#流程控制詳解

    這篇文章主要介紹了C#流程控制詳解,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2022-07-07
  • c#中的virtual方法及應(yīng)用場(chǎng)景分析

    c#中的virtual方法及應(yīng)用場(chǎng)景分析

    在 C# 中,virtual?關(guān)鍵字用于修飾方法、屬性、索引器或事件,這篇文章主要介紹了c#中的virtual方法及應(yīng)用場(chǎng)景分析,需要的朋友可以參考下
    2025-03-03
  • C#給Word不同頁(yè)面設(shè)置不同背景

    C#給Word不同頁(yè)面設(shè)置不同背景

    這篇文章主要介紹了C#給Word不同頁(yè)面設(shè)置不同背景,文章圖文講解的很清晰,有對(duì)于這方面不懂得同學(xué)可以學(xué)習(xí)下
    2021-02-02
  • c#中 String和string的區(qū)別介紹

    c#中 String和string的區(qū)別介紹

    String和string的區(qū)別有哪些,想有很多朋友都不知道吧,在本文將為大家詳細(xì)介紹下,感興趣的朋友可以參考下,希望對(duì)大家有所幫助
    2013-10-10

最新評(píng)論

桓台县| 扶余县| 维西| 泸州市| 昆明市| 墨玉县| 纳雍县| 通化市| 新余市| 黎川县| 象州县| 灵丘县| 兴宁市| 时尚| 象州县| 伊宁市| 平顺县| 永宁县| 甘南县| 兴仁县| 丘北县| 阿图什市| 广州市| 屯门区| 北流市| 静海县| 福海县| 开远市| 潢川县| 进贤县| 新蔡县| 电白县| 德格县| 方城县| 枣庄市| 夏河县| 定安县| 阳信县| 梅河口市| 清水河县| 东光县|