使用DFS打印至少两个路径可访问的所有节点

时间:2016-09-12 15:51:42

标签: algorithm graph-theory depth-first-search

我们如何修改以下DFS算法,以便它打印出来自起始节点的至少两条路径可访问的所有节点?

DFS(G,s):
        foreach v in V do
            color[v] <- white; p[v] <- nil
        DFS-Visit(s)

    DFS-Visit(u)
        color[u] <- grey
        foreach v in Adj[u] do
            if color[v] = white then 
                p[v] = u; DFS-Visit(v)
        color[u] <- black

E.g。如果图形是树,则不会打印任何节点。如果图形是循环,则将打印所有节点。

2 个答案:

答案 0 :(得分:1)

尽管可以通过运行BFS而不是DFS轻松实现,但也可以通过运行 DFS两次来实现。

第一次时,在访问顶点u时,我们希望标记vAdj[u]gray中的每个blackspecial。这意味着此顶点之前已被访问过,这意味着它至少有两个路径。我们将通过向顶点添加另一个字段来实现此目的,我们将其命名为DFS(G,s): foreach v in V do color[v] <- white; parent[v] <- nil; special[v] <- false DFS-Visit(s) DFS-Visit(u) color[u] <- grey foreach v in Adj[u] do if color[v] = white then parent[v] = u; DFS-Visit(v) if color[v] = gray or color[v] = black special[v] <- true color[u] <- black

v

现在我们知道至少有两条路径可以访问special[v] == true的每个顶点special。 但这还不够 - 如果你想到一个循环,我们只会将我们开始的顶点标记为special。这就是我们需要另一次DFS运行的原因。

因此,我们还要标记具有已经标记为DFS(G,s): foreach v in V do color[v] <- white; parent[v] <- nil DFS-Visit(s) DFS-Visit(u) color[u] <- grey foreach v in Adj[u] do if special[u] = true special[v] = true if color[v] = white then parent[v] = u; DFS-Visit(v) color[u] <- black 的顶点的路径的所有顶点。我们可以通过运行另一个DFS

来实现此目的
v

最后,您可以打印具有special[v] == true

的每个顶点using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Configuration; using Microsoft.Xrm.Sdk; using Microsoft.Xrm.Tooling.Connector; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { int choice; CrmServiceClient crmConn = new CrmServiceClient(ConfigurationManager.ConnectionStrings["CRM"].ConnectionString); IOrganizationService crmService = crmConn.OrganizationServiceProxy; Entity acc = new Entity("account"); String account_name; Console.WriteLine("Press 1 to Create a new account or Press 2 to view list of available accounts."); choice = Convert.ToInt32(Console.ReadLine()); switch (choice) { case 1: Console.WriteLine("Enter Name of Account to Create ?"); account_name = Console.ReadLine(); acc["name"] = account_name; crmService.Create(acc); Console.WriteLine("*****An account with name {0} is created successfully*****", account_name); Console.WriteLine(); Console.WriteLine("Press any key to exit.."); Console.ReadKey(); break; case 2: //code to display list of all account names in CRM. Console.ReadKey(); break; default: Console.WriteLine("Wrong input..."); Console.ReadKey(); break; } } } }

答案 1 :(得分:1)

第一步是写下我们可以想到的与我们正在寻找的属性相关的所有规则:从存在节点的s中存在多个不同的路径。

  1. 如果u!= v两者都有w的路径,则至少有两条路径到达w。
  2. 如果你有通往u的路径,则至少有两条路径到达你。
  3. 如果你指向v,并且通过两条路径到达u,则至少有两条路径到达v。
  4. 对于至少两个路径到达的每个节点,上述三个条件中至少有一个成立。
  5. 对于诸如s-> a,s-> b,a-> c,b-> c,c-> d的情况,我们需要条件1,以便打印c。对于像s - &gt;这样的情况,我们需要条件2。 x - &gt; y - &gt; s,打印出s。我们需要条件三,以便例如在上述情况下,打印d,x和y。条件4表明这些条件已足够。

    我们可以通过更改我们的&#34;转身&#34;来修改DFS。条件。而不是&#34;转身&#34;当我们看到我们已经访问过的节点时,我们只是改变状态;现在我们不是寻找看不见的节点,而是从这个节点做一个DFS,用于我们以前见过的那些节点。在这个元DFS期间,如果我们看到之前已经看过两次,我们会回头;如果我们看到一个我们以前看不到的东西,我们会将其标记为不止一次,并继续前进。元DFS完成后,我们将返回原始DFS。因此节点有三个条件,我们有两个状态可以跟踪。条件是:

    • 看不见
    • 见过一次
    • 不止一次见过

    状态是:

    • 寻找看不见的
    • 寻找没见过两次

    以下是我们处理6种可能情况的方法:

    1. 寻找看不见的东西,找到看不见的东西:标记为曾经见过;仍在寻找当前节点看不见的东西
    2. 寻找看不见的,发现看到:标记不止一次;打印节点;切换到从当前节点查找一次
    3. 寻找看不见的,找不到一次:死胡同,结束递归分支
    4. 寻找没见过两次,找不到看见:标记不止一次;打印节点;继续寻找没见过两次
    5. 寻找没有看过两次,找到一次见过:标记不止一次;打印节点;继续寻找没见过两次
    6. 寻找没见过两次,发现不止一次:死胡同,结束递归分支
    7. 规则1和2需要行为2.行为4和5是规则3所需要的。行为1,3和6耗尽了我们的其他可能性,并确保在这些情况下规则4成立。