Пример #1
0
        // Finds the path that gets the maximum flow
        // This runs in O(2 * edges.Count) time. As edges get destroyed, it will run progressively faster.
        //		Edges with (flow == capacity) will not be assessed, if another edge connects to that edge's target node, the target will be assessed at that time.
        //		Nodes with no edges going into them will not be assessed, thus all of their exiting edges will not be assessed either.
        static List <NetworkLink> GetMaxFlowPath(NetworkNode sourceNode, NetworkNode finalNode, out int maxFlow)
        {
            Dictionary <NetworkNode, NetworkLink> flowPathTable   = new Dictionary <NetworkNode, NetworkLink>();
            Dictionary <NetworkNode, int>         flowAmountTable = new Dictionary <NetworkNode, int>();
            HashSet <NetworkNode> nodesAddedButNotRecorded        = new HashSet <NetworkNode>();
            Stack <NetworkLink>   cycleEdges = new Stack <NetworkLink>();

            // add the final node to the tables. This way, the algorithm will stop at the final node.
            flowPathTable.Add(finalNode, null);
            flowAmountTable.Add(finalNode, int.MaxValue);

            // recursively add nodes to the table, starting at the source node.
            AddNodeToTables(sourceNode, ref nodesAddedButNotRecorded, ref flowPathTable, ref flowAmountTable, ref cycleEdges);

            // reverse the stack in order to get the cycle links that are closest to the end.
            if (cycleEdges.Count > 0)
            {
                cycleEdges = (Stack <NetworkLink>)cycleEdges.Reverse();
            }

            // correct the table if necessary to incorporate the cycle edges.
            while (cycleEdges.Count > 0)
            {
                var edge = cycleEdges.Pop();

                // the new flow is the calculated using the cycle edge.
                int flow = Math.Min(flowAmountTable[edge.target], edge.capacity - edge.flow);

                // if the new flow is greater than the old one, use the new flow and the new direction.
                if (flow > flowAmountTable[edge.source])
                {
                    flowPathTable[edge.source]   = edge;
                    flowAmountTable[edge.source] = flow;
                }
            }

            // get the maxFlow for the path
            maxFlow = flowAmountTable[sourceNode];

            // if there is 0 maxFlow, then there is no path to the target anymore.
            if (maxFlow == 0)
            {
                return(null);
            }

            // build the path now that the tables are complete
            List <NetworkLink> path = new List <NetworkLink>();

            // set the first entry of the path to the source node's best choice edge.
            path.Add(flowPathTable[sourceNode]);

            // Add the most recent edge's target's best choice edge to the path.
            while (path[path.Count - 1].target != finalNode)
            {
                path.Add(flowPathTable[path[path.Count - 1].target]);
            }

            return(path);
        }
Пример #2
0
        // adds the passed node to the tables recursively
        static void AddNodeToTables(
            NetworkNode node,
            ref HashSet <NetworkNode> nodesAddedButNotRecorded,
            ref Dictionary <NetworkNode, NetworkLink> flowPathTable,
            ref Dictionary <NetworkNode, int> flowAmountTable,
            ref Stack <NetworkLink> cycleEdges
            )
        {
            nodesAddedButNotRecorded.Add(node);

            NetworkLink bestChoice = null;
            int         bestFlow   = 0;

            // search the outward links for the link which offers the best path to the target.
            foreach (NetworkLink link in node.linksOut)
            {
                // if the link cannot pass anymore flow, skip it.
                if (link.capacity - link.flow == 0)
                {
                    continue;
                }

                //	if the target of this link has been added already,
                //		and there is no entry for it in the flow path table,
                //		then this is a cycle edge. Don't evaluate it now.
                if (nodesAddedButNotRecorded.Contains(link.target))
                {
                    cycleEdges.Push(link);
                    continue;
                }
                else if (!flowPathTable.ContainsKey(link.target))
                {
                    AddNodeToTables(link.target, ref nodesAddedButNotRecorded, ref flowPathTable, ref flowAmountTable, ref cycleEdges);
                }

                //	if the minimum between the possible increase in flow on this link
                //		and the possible increase in flow for the path to the target
                //		following this edge is greater than that of the other links
                //		investigated so far, select this one as the best choice.
                int flow = Math.Min(link.capacity - link.flow, flowAmountTable[link.target]);
                if (flow > bestFlow)
                {
                    bestChoice = link;
                    bestFlow   = flow;
                }
            }

            //	add the best choice and best flow to the tables.
            //		if there were no outward links, or all of their (capacity - flow)s were 0, bestFlow will be 0.
            flowPathTable.Add(node, bestChoice);
            flowAmountTable.Add(node, bestFlow);

            nodesAddedButNotRecorded.Remove(node);
        }
Пример #3
0
        static List <NetworkLink> FindMinimumCut(NetworkNode source)
        {
            List <NetworkLink> minCut = new List <NetworkLink>();
            List <NetworkNode> nodes  = new List <NetworkNode>();

            // add targets of the source node where the link between them has at least 1 flow.
            foreach (NetworkLink l1 in source.linksOut)
            {
                foreach (NetworkLink l2 in l1.target.linksOut)
                {
                    minCut.Add(l2);
                }
            }

            /*
             * for(int i = 0; i < nodes.Count; i++)
             * {
             *      foreach(NetworkLink l in nodes[i].linksOut)
             *      {
             *              // if the flow in the link is not full,
             *              // and if the target of the link has not already been added to the node list, add it.
             *              if(l.flow != l.capacity && !nodes.Contains(l.target))
             *              {
             *                      nodes.Add(l.target);
             *              }
             *
             *              // otherwise, if the link is full, then the link is part of the minimum cut.
             *              else if(l.flow == l.capacity)
             *              {
             *                      minCut.Add(l);
             *              }
             *      }
             * }
             */

            return(minCut);
        }
Пример #4
0
        //	Creates a directed network graph from a file. Automatically sets each link's capacity using an RNG.
        //	Generates a source and target node, connecting them at maximum flow to 'K' other nodes in the graph.
        //		fileName: name of the file containing the graph data.
        //		vertextCount: the number of verteces contained in the file.
        //		edgeCount: the number of edges contained in the file.
        //		minCapacity: the minimum capacity of the links in the graph. These will be randomly generated.
        //		maxCapacity: the maximum capacity of the links in the graph. These will be randomly generated.
        //		K: the number of edges that the generated source and target nodes will have going into, and out of, respectfully.
        //		SEED: the random number generator seed.
        public NetworkGraph(string fileName, int vertexCount, int edgeCount, int minCapacity, int maxCapacity, int K, int SEED)
        {
            Random random = new Random(SEED);

            vertices = new NetworkNode[vertexCount + 2];        // plus 2 for the source and target nodes that will be generated.
            edges    = new NetworkLink[edgeCount + 2 * K];      // plus 2 * K for the K edges going into and out of the source and target.
            maxFlow  = 0;

            // begin reading and parsing the file.
            using (Stream Stream = File.OpenRead(fileName))
                using (StreamReader reader = new StreamReader(Stream))
                {
                    string[] sepNodes = { "node [", "edge [" };
                    //Index 0 is everything before nodes, Don't need;
                    //Index nodes.Length is the edges, parsed after;
                    string[] arrayStrNodes = reader.ReadToEnd().Split(sepNodes, StringSplitOptions.RemoveEmptyEntries);
                    for (int i = 1; i < arrayStrNodes.Length; i++)
                    {
                        string[] arrNode = arrayStrNodes[i].Split('\n');

                        bool   isEdge    = false;
                        int    id        = -1;
                        float  longitude = -1;
                        float  latitude  = -1;
                        string label     = "";
                        int    source    = -1;
                        int    target    = -1;

                        for (int j = 1; j < arrNode.Length; j++)
                        {
                            if (arrNode[j].Length > 4)
                            {
                                switch (arrNode[j][4])
                                {
                                case 'i':
                                    string strID = arrNode[j].Substring(7);
                                    if (strID.Length > 1 && strID[1] == 'e')//added length check for id 0 of nodes
                                    {
                                        isEdge = true;
                                        id     = Convert.ToInt32(strID.Substring(2, strID.Length - 4));
                                    }
                                    else
                                    {
                                        id = Convert.ToInt32(strID);
                                    }
                                    break;

                                case 'L':
                                    if (arrNode[j][5] == 'o')//Longitude
                                    {
                                        longitude = (float)Convert.ToDouble(arrNode[j].Substring(14));
                                    }
                                    else//Latitude
                                    {
                                        latitude = (float)Convert.ToDouble(arrNode[j].Substring(13));
                                    }
                                    break;

                                case 'l':
                                    label = arrNode[j].Substring(11, arrNode[j].Length - 13);
                                    break;

                                case 's':
                                    source = Convert.ToInt32(arrNode[j].Substring(10));
                                    break;

                                case 't':
                                    target = Convert.ToInt32(arrNode[j].Substring(10));
                                    break;
                                }
                            }
                        }
                        if (id > -1)
                        {
                            if (isEdge)
                            {
                                NetworkLink link = new NetworkLink(vertices[source], vertices[target]);
                                edges[id]     = link;
                                link.capacity = random.Next(minCapacity, maxCapacity + 1);
                            }
                            else
                            {
                                NetworkNode node = new NetworkNode(label, longitude, latitude);
                                vertices[id] = node;
                            }
                        }
                    }
                }

            //Declaring the source and target nodes
            //Doesn't really matter "where" they are
            source = new NetworkNode("source", 0, 0);
            target = new NetworkNode("target", 0, 0);

            vertices[vertexCount]     = source;
            vertices[vertexCount + 1] = target;

            Random rand = new Random(SEED);
            //List to keep track of the nodes that are conncected to by the source and target
            List <NetworkNode> sourceLinks = new List <NetworkNode>(K);
            List <NetworkNode> targetLinks = new List <NetworkNode>(K);
            //Index to keep track of where to add into the edges array
            int LinkIndex = 1;

            //generating the edges for source edges
            while (sourceLinks.Count < sourceLinks.Capacity)
            {
                int i = rand.Next(0, vertexCount);
                if (!sourceLinks.Contains(vertices[i]))
                {
                    sourceLinks.Add(vertices[i]);
                    edges[edgeCount - 1 + LinkIndex]          = new NetworkLink(source, vertices[i]);
                    edges[edgeCount - 1 + LinkIndex].capacity = 20;
                    LinkIndex++;
                }
            }
            //generating edges for target edges
            //Compares to make sure the target does not connect to any of the same nodes as the source.
            while (targetLinks.Count < targetLinks.Capacity)
            {
                int i = rand.Next(0, vertexCount);
                if (!sourceLinks.Contains(vertices[i]) && !targetLinks.Contains(vertices[i]))
                {
                    targetLinks.Add(vertices[i]);
                    edges[edgeCount - 1 + LinkIndex]          = new NetworkLink(vertices[i], target);
                    edges[edgeCount - 1 + LinkIndex].capacity = 20;
                    LinkIndex++;
                }
            }
            //Console.WriteLine("Built graph from " + fileName + ". Nodes: " + vertexCount + " Links: " + edgeCount + ".");
        }
Пример #5
0
        static void ReduceNode(NetworkNode node, int deficit, bool forward)
        {
            // if the node has no more links to follow, just quit.
            if ((forward ? node.linksOut.Count : node.linksIn.Count) == 0)
            {
                return;
            }

            // try to find a link that is large enough to take the whole flow hit.
            // else, fill a list with links that have flow to add up to the deficit.
            NetworkLink        toReduce   = null;
            List <NetworkLink> reduceList = new List <NetworkLink>();

            foreach (NetworkLink link in (forward ? node.linksOut : node.linksIn))
            {
                if (link.flow == deficit)
                {
                    toReduce = link;
                    break;
                }
                else if (link.flow > deficit)
                {
                    toReduce = link;
                }
                else if (link.flow != 0 && toReduce == null)
                {
                    reduceList.Add(link);
                }
            }

            // if there is a link with an equal or greater flow than the deficit, simply reduce that one.
            if (toReduce != null)
            {
                //Console.WriteLine("\tReduced by " + deficit + ": " + toReduce);

                toReduce.flow -= deficit;
                ReduceNode((forward ? toReduce.target : toReduce.source), deficit, forward);
            }

            // otherwise, search through the reduce list for links that will add up their flows to the deficit and reduce each of them.
            else if (reduceList.Count > 0)
            {
                int i = 0;
                while (deficit != 0)
                {
                    int flowDeficit = reduceList[i].flow;
                    if (flowDeficit > deficit)
                    {
                        flowDeficit = deficit;
                    }
                    deficit -= flowDeficit;

                    //Console.WriteLine("\tReduced by " + flowDeficit + ": " + reduceList[i]);

                    reduceList[i].flow -= flowDeficit;
                    ReduceNode((forward ? reduceList[i].target : reduceList[i].source), flowDeficit, forward);

                    i++;
                }
            }
        }