/// <summary> /// 添加一条相邻的边,有可能是前向或者后向 /// </summary> public void InsertEdge(LGEdge e) { if (e.Source.Id == this.Id) { nedges.Add(e); } if (e.Destination.Id == this.Id) { pedges.Add(e); } }
/// <summary> /// 添加边 /// </summary> public void InsertEdge(LCNode lcnode, int sid, int did) { if (sid <= 0 || sid > vertexs.Count) { throw new ArgumentOutOfRangeException(); } if (did <= 0 || did > vertexs.Count) { throw new ArgumentOutOfRangeException(); } //Console.Write("edge {0:d} {1:d}\n", sid, did); LGEdge e = new LGEdge(lcnode, vertexs[sid - 1], vertexs[did - 1]); vertexs[sid - 1].InsertEdge(e); vertexs[did - 1].InsertEdge(e); edges.Add(e); }
/// <summary> /// 设置边标记中点标号的对应位(设置为1) /// </summary> /// <param name="lge">给定的边</param> /// <param name="id">给定的点标号</param> /// <returns>对应的标记</returns> private int _EdgeSetFlag(LGEdge lge, int id) { if (id <= 32) { return(lge[1] |= (1 << (id - 1))); } if (id <= 64) { return(lge[2] |= (1 << (id - 33))); } if (id <= 96) { return(lge[3] |= (1 << (id - 65))); } if (id <= 128) { return(lge[4] |= (1 << (id - 97))); } throw new IndexOutOfRangeException(); }
/// <summary> /// 得到边标记中点标号的对应位 /// </summary> /// <param name="lge">给定的边</param> /// <param name="id">给定的点标号</param> /// <returns>对应的位的值(0或1,1返回true)</returns> private bool _EdgeGetFlag(LGEdge lge, int id) { if (id <= 32) { return(((lge[1] >> (id - 1)) & 1) != 0); } if (id <= 64) { return(((lge[2] >> (id - 33)) & 1) != 0); } if (id <= 96) { return(((lge[3] >> (id - 65)) & 1) != 0); } if (id <= 128) { return(((lge[4] >> (id - 97)) & 1) != 0); } throw new IndexOutOfRangeException(); }
/// <summary> /// 判断这个边的所有标记是否为空 /// </summary> /// <param name="lge">给定的边</param> /// <returns>是否为空,为空返回true</returns> private bool _EdgeEmptyFlag(LGEdge lge) { return(lge[1] == 0 && lge[2] == 0 && lge[3] == 0 && lge[4] == 0); } /// <summary>
/// <summary> /// 检查是否混联错误 /// </summary> /// <returns>是否存在混联错误</returns> /// <detail> /// 当存在入度不等于出度的环时,说明这个环存在分支,即符合混联错误的条件 /// 入度大于出度时存在向内的分支,入度小于出度时存在向外的分支 /// 所以可以检查所有的联通分量,判断是否都合法 /// 合法的条件为in(T)-out(S)+sum(in(a)-out(a)) == 0, a为环内不包含原终点的点 /// in(T)是相对于终点T的出度,即所有能到达T的边的总数 /// out(S)是相对于起点S的出度,即所有能从S到达该点的边的总数 /// </detail> public bool CheckFusionCircuit() { btflag = new int[vertexs.Count(), 4]; // 枚举每个点作为环的原点 foreach (LGVertex lgv1 in vertexs) { // 出度为1的点不可能是环的原点 if (lgv1.Edges.Count <= 1) { continue; } /* * in(T)和out(S)是无法直接获得的,需要从起点出发访问所有的边 * 并且点和边上的四个标记以位的方式存储这条边是否到达某个节点 * 标记1存储编号1-32,标记2存33-64,以此类推 * 对于每个相对于S的in(T),找到标记过的后向边的数量 * 对于每个相对于T的out(S),找出在对应位标记的前向边的数量 */ foreach (LGVertex lgv2 in vertexs) { lgv2[1] = lgv2[2] = lgv2[3] = lgv2[4] = 0; } foreach (LGEdge lge in edges) { lge[1] = lge[2] = lge[3] = lge[4] = 0; } _EdgeSearch(lgv1); LGEdge flagedge = new LGEdge(null, null, null); foreach (LGVertex lgv2 in vertexs) { // 该点应不为起点 if (lgv2.Id == lgv1.Id) { continue; } int sum = 0, sumin = 0, sumout = 0; flagedge[1] = flagedge[2] = flagedge[3] = flagedge[4] = ~0; // 检查终点的所有后向边,统计in(T) foreach (LGEdge lge in lgv2.BackEdges) { if (!_EdgeEmptyFlag(lge)) { sumin++; } } // 检查起点的所有前向边,统计out(S) foreach (LGEdge lge in lgv1.Edges) { if (_EdgeGetFlag(lge, lgv2.Id)) { sumout++; for (int i = 1; i <= 4; i++) { flagedge[i] &= lge[i]; } } } // 检查终点的所有前向边,剔除掉后面的桥点 foreach (LGEdge lge in lgv2.Edges) { for (int i = 1; i <= 4; i++) { flagedge[i] &= ~lge[i]; } } // 若不能构成两条以上的路径则忽略 if (sumin < 2 || sumout < 2) { continue; } // 计算in(T)-out(S) sum = sumin - sumout; // 检查所有能够到达终点的点,统计sum(in(a)-out(a)) bool hasbridge = false; foreach (LGVertex lgv3 in vertexs) { if (lgv3.Id == lgv1.Id) { continue; } if (lgv3.Id == lgv2.Id) { continue; } // 该点是连通分量的桥点 if (_EdgeGetFlag(flagedge, lgv3.Id)) { hasbridge = true; break; } if (_VertexGetFlag(lgv3, lgv2.Id)) { sum += lgv3.BackEdges.Count() - lgv3.Edges.Count(); } } // 如果不存在桥点,并且不满足等式则混连错误 if (!hasbridge && sum != 0) { return(true); } } } return(false); }