图形的可达性

时间:2016-09-16 19:10:57

标签: c# graph reachability transitive-closure

几个月前,我参加了CodeForces的竞赛,自那以后我一直在尝试不同的解决方案。

问题基本上由包含有向图的节点和边的输入组成。基本上,如果:A指向B,B指向C,C指向D,那么我们可以说A也指向C,而D则指向B,指向D.这个想法。

我现在的问题是,我尝试了一些不同的解决方案,其中一些解决方案但仍遇到时间限制。另一个是我最好的尝试,使其有效,但它在一些测试失败。不幸的是,我不允许看一下测试。

这是我的代码的骨架,如果你不想在这里查看整个代码,下面会提到TransitiveClosure()函数:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace D.Find_Path3
{
    class Program
    {
        public class ReachabilityGraph
        {
            // placeholder
            public void TransitiveClosure() { }

            private Node[] _nodesArr;
            private HashSet<Node> _validNodes;
            private bool[,] _transitiveClosure;

            private int _nodes;
            private int _edges;

            public int Nodes { get { return _nodes; } }
            public int Edges { get { return _edges; } }

            public ReachabilityGraph(int nodes)
            {
                _nodes = nodes;

                _nodesArr = new Node[nodes];
                _validNodes = new HashSet<Node>();
                _transitiveClosure = new bool[nodes, nodes];
            }

            public void AddEdge(int u, int v)
            {
                if (_nodesArr[u] == null)
                    _nodesArr[u] = new Node(u);
                _validNodes.Add(_nodesArr[u]);

                if (_nodesArr[v] == null)
                    _nodesArr[v] = new Node(v);

                if (_nodesArr[u].AddChild(_nodesArr[v]))
                    ++_edges;
            }

            public bool IsConnected(int u, int v)
            {
                return _transitiveClosure[u, v];
            }

            class Node
            {
                private Lazy<HashSet<Node>> children = new Lazy<HashSet<Node>>(() => new HashSet<Node>());

                public int Value { get; private set; }
                public IEnumerable<Node> Children { get { return children.IsValueCreated ? children.Value : Enumerable.Empty<Node>(); } }
                public bool HasChildren { get { return children.IsValueCreated && children.Value.Count != 0; } }

                public Node(int value)
                {
                    Value = value;
                }

                public bool AddChild(Node u)
                {
                    return children.Value.Add(u);
                }

                public override bool Equals(object obj)
                {
                    var other = obj as Node;
                    return other != null && other.Value == Value;
                }

                public override int GetHashCode()
                {
                    return Value;
                }

                public override string ToString()
                {
                    return Value.ToString();
                }

                public static implicit operator int(Node n)
                {
                    return n.Value;
                }
            }
        }

        static void Main(string[] args)
        {
            // N: number of nodes
            // M: number of edges
            var NM = new int[2];
            GetIntsFromConsole(NM);

            var graph = new ReachabilityGraph(NM[0]);

            // add edges to graph
            var uv = new int[2];
            for (var i = 0; i < NM[1]; ++i)
            {
                GetIntsFromConsole(uv);
                graph.AddEdge(uv[0] - 1, uv[1] - 1);
            }

            graph.TransitiveClosure();

            // how many queries
            var Q = int.Parse(Console.ReadLine());
            for (var i = 0; i < Q; ++i)
            {
                GetIntsFromConsole(uv);
                Console.WriteLine(graph.IsConnected(uv[0] - 1, uv[1] - 1) ? "YES" : "NO");
            }
        }

        static void GetIntsFromConsole(int[] array)
        {
            var query = Console
                .ReadLine()
                .Split(' ')
                .Select(a => int.Parse(a));

            int i = 0;
            foreach (var item in query)
                array[i++] = item;
        }
    }
}

这是TransitiveClosure的有效但缓慢的尝试:

    public void TransitiveClosure()
    {
        foreach (var u in _validNodes)
        {
            var stack = new Stack<Node>();
            stack.Push(u);

            while (stack.Any())
            {
                var v = stack.Pop();
                _transitiveClosure[u, v] = true;

                foreach (var temp in v.Children)
                    if (!_transitiveClosure[u, temp])
                        stack.Push(temp);
            }
        }
    }

我也尝试以递归方式进行,但这恰好是错误的,我不确定它背后的逻辑部分是什么错误:

            public void TransitiveClosure()
            {
                var stack = new Stack<Node>();

                foreach (var u in _validNodes)
                {
                    if (!_transitiveClosure[u, u])
                    {
                        TransitiveClosure(u, stack);
                        stack.Clear();
                    }
                }
            }

            private Stack<Node> TransitiveClosure(Node u, Stack<Node> subStack)
            {
                if (u.HasChildren && !_transitiveClosure[u, u])
                {
                    _transitiveClosure[u, u] = true;
                    var superStack = new Stack<Node>();

                    foreach (var child in u.Children)
                    {
                        var result = TransitiveClosure(child, subStack);

                        while (result.Any())
                        {
                            var v = result.Pop();

                            superStack.Push(v);
                            _transitiveClosure[u, v] = true;
                        }
                    }

                    subStack = superStack;
                }

                subStack.Push(u);
                return subStack;
            }

我的代码使用邻接矩阵的其他尝试,以及其他可以在此处找到,如果相关:http://pastebin.com/A0a186V5

我很感激您对此的意见,我可以采取哪些措施加快速度。此外,如果你能告诉我我能做些什么来让我的第二次递归尝试工作。请原谅我在代码中缺少评论。

我不确定这可以实现的最佳复杂性,所以请引导我走上正轨。也许还有一些我不知道的其他算法,我可以看一下。

谢谢你,对不起这篇长篇文章感到抱歉!

0 个答案:

没有答案