/// <summary>
        /// 构建列车弧
        /// </summary>
        /// <param name="arcCount"></param>
        private void create_Line_T_S_Arcs(ref int arcCount)
        {
            for (int i = 0; i < T_S_NodeList.Count - 1; i++)
            {
                for (int j = i + 1; j < i + 2 /*T_S_NodeList.Count*/; j++)
                {
                    // 因为在创建并添加点的时候,同一Line的出发点和到达点是先后创建添加的,所以内层不用循环
                    T_S_Node startPoint = T_S_NodeList[i];
                    T_S_Node endPoint   = T_S_NodeList[j];

                    if (startPoint.LineID == endPoint.LineID &&
                        startPoint.PointType == 1 && endPoint.PointType == 2 &&
                        ((startPoint.TimeCode < 1440 && endPoint.TimeCode < 1440) ||
                         (startPoint.TimeCode >= 1440 && endPoint.TimeCode >= 1440)))
                    {
                        T_S_Arc t_s_arc = new T_S_Arc();
                        t_s_arc.Init_db(startPoint, endPoint,
                                        arcCount, startPoint.LineID, startPoint.RountingID, startPoint.TrainCode,
                                        startPoint.ID, endPoint.ID,
                                        startPoint.StaCode, endPoint.StaCode,
                                        startPoint.TimeCode, endPoint.TimeCode,
                                        1);//1——运行弧

                        T_S_ArcList.Add(t_s_arc);
                        startPoint.Out_T_S_ArcList.Add(t_s_arc);

                        arcCount++;
                    }
                }
            }
        }
        public void Init_db(T_S_Node startPoint_, T_S_Node endPoint_,
            int id_, int lineID_, int routingID_, string trainCode_,
            int startPointID_, int endPointID_,
            string startStation_, string endStation_,
            int startTime_, int endTime_,
            int arcType_) {

            StartPoint = startPoint_;
            EndPoint = endPoint_;

            iD = id_;
            lineID = lineID_;
            rountingID = routingID_;
            trainCode = trainCode_;

            startPointID = startPointID_;
            endPointID = endPointID_;

            startStaCode = startStation_;
            endStaCode = endStation_;

            startTimeCode = startTime_;
            endTimeCode = endTime_;

            arcType = arcType_;

            len = endTimeCode - startTimeCode;
        }
        public void Init_db(int id, int prevID,
            int lineID, int routingID, string trainCode, 
            string station, int timeCode,
            int pointType, string OStation,
            int superID, int prevSuperID,
            T_S_S_Node prevNode,
            T_S_Node superPoint, T_S_Node prevSuperPoint) {

            this.iD = id;
            this.prevID = prevID;

            this.lineID = lineID;
            this.rountingID = routingID;
            this.trainCode = trainCode;

            this.staCode = station;
            this.timeCode = timeCode;

            this.pointType = pointType;
            this.OStation = OStation;

            this.superPointID = superID;
            this.prevSuperID = prevSuperID;

            this.PrevNode = prevNode;
            this.SuperPoint = superPoint;
            this.PrevSuperPoint = prevSuperPoint;
        }
        public void CreateT_S_S_Network_db(/*CrewRule crewRule*/)
        {
            Debug.Assert(BasicTimeRules.MinConnTime != -1);

            List <T_S_S_Node>  allStateNodes = new List <T_S_S_Node>();
            Queue <T_S_S_Node> queue         = new Queue <T_S_S_Node>();

            initVirStartNode(ref allStateNodes, ref queue);

            //List<T_S_S_Node> tempDNodeList = new List<T_S_S_Node>();
            //Dictionary<int, T_S_S_Node> IDToNodeDict = new Dictionary<int, T_S_S_Node>();
            //foreach (var startNode in allStateNodes) {
            //    IDToNodeDict.Add(startNode.ID, startNode);
            //}

            int debug_count = 100000;
            int debug_iter  = 0;

            int        nodeCount = CrewBaseList.Count * 2; //其余时空状态点的编号从乘务基地虚拟起终点之后开始
            T_S_S_Node top_node;

            while (queue.Count > 0)
            {
                //if (--debug_count < 0) {
                //    debug_count = 100000;
                //    debug_iter++;

                //    Console.WriteLine("current Queue.Count is [{0}]", queue.Count);
                //    Console.WriteLine("debug iter is [{0}]", debug_iter);
                //}

                top_node = queue.Dequeue();
                //Console.WriteLine(Logger.stateNodeInfoToStr(top_node, OutputMode.console));
                //if (debug_iter >= 10) {
                //    if (debug_count  < 3000) {
                //        Console.WriteLine("cur debug count is [{0}]", debug_count);
                //    }
                //}
                T_S_Node       cur_super_point = top_node.SuperPoint;
                List <T_S_Arc> out_T_S_ArcList = cur_super_point.Out_T_S_ArcList;
                for (int i = 0; i < out_T_S_ArcList.Count; i++)
                {
                    T_S_Arc cur_t_s_arc = out_T_S_ArcList[i];


                    // debug
                    //if (top_node.PassLine.Contains(30)
                    //    && top_node.PassLine.Contains(143)
                    //    //&& top_node.PassLine.Contains(64)
                    //    //&& top_node.PassLine.Contains(157)
                    //    && cur_t_s_arc.EndTimeCode == 1029
                    //    && cur_t_s_arc.ArcType == 21) {
                    //    Console.WriteLine("top_node.PenaltyMealViolate:" + top_node.PenaltyMealViolate);
                    //}

                    //end debug

                    T_S_S_Node extendStateNode = new T_S_S_Node();
                    extendStateNode.Resources = new Resource(lineList.Count);

                    if (!FeasibleDriveTime(top_node, cur_t_s_arc, ref extendStateNode.Resources))
                    {
                        continue;
                    }
                    if (!FeasibleDayCrewTime(top_node, cur_t_s_arc, ref extendStateNode.Resources))
                    {
                        continue;
                    }
                    // 交路退乘点必须与出乘点相同 (必须回基地的约束)
                    if (cur_t_s_arc.ArcType == 32 &&
                        cur_t_s_arc.EndStaCode != top_node.OStation)
                    {
                        continue;
                    }
                    // 用餐软约束
                    // 必须是非运行弧,才可能可以用餐
                    if (cur_t_s_arc.ArcType != 1)
                    {
                        handleMealConstraint(top_node, cur_t_s_arc, ref extendStateNode);
                        // NOTE:可以处理一下,若当前弧用餐成功,则标记为用餐弧
                    }
                    else
                    {
                        extendStateNode.Resources.SetLunchStatus(top_node.Resources.LunchStatus);
                        extendStateNode.Resources.SetDinnerStatus(top_node.Resources.DinnerStatus);
                    }

                    // extendStartNode基本属性赋值
                    extendStateNode.Init_db(nodeCount, top_node.ID,
                                            cur_t_s_arc.LineID, cur_t_s_arc.RountingID, cur_t_s_arc.TrainCode,
                                            cur_t_s_arc.EndStaCode, cur_t_s_arc.EndTimeCode,
                                            cur_t_s_arc.ArcType, top_node.OStation,
                                            cur_t_s_arc.EndPointID, cur_super_point.ID,
                                            top_node, cur_t_s_arc.EndPoint, cur_super_point);

                    // 还有其他属性
                    // 1 途径运行线
                    extendStateNode.PassLine.AddRange(top_node.PassLine);
                    if (cur_t_s_arc.ArcType == 1)
                    {
                        extendStateNode.PassLine.Add(cur_t_s_arc.LineID);
                        extendStateNode.Resources.LinesVisitedArray[cur_t_s_arc.LineID - 1] += 1;
                    }
                    // 2 起终点的编号
                    if (cur_t_s_arc.ArcType == 31)
                    {
                        extendStateNode.Price = 1440;

                        Debug.Assert(extendStateNode.PenaltyMealViolate == 0);
                    }
                    else if (cur_t_s_arc.ArcType == 32)
                    {
                        extendStateNode.ID    = BaseStationToODIDDict[extendStateNode.StaCode][1];
                        extendStateNode.Price = 0;
                        --nodeCount; // 终点有自己的编号,所以此次不用增加nodeCount;
                        Debug.Assert(extendStateNode.PenaltyMealViolate == 0);
                    }
                    else if (cur_t_s_arc.ArcType == 33)
                    {
                        extendStateNode.ID    = BaseStationToODIDDict[extendStateNode.StaCode][1];
                        extendStateNode.Price = virtualRoutingCost;
                        --nodeCount; // 终点有自己的编号,所以此次不用增加nodeCount;
                        Debug.Assert(extendStateNode.PenaltyMealViolate == 0);
                    }
                    else
                    {
                        extendStateNode.Price = cur_t_s_arc.Len;// + extendStateNode.PenaltyMealViolate;
                        //后续对弧再赋值Penalty
                    }


                    // 比较标号优劣
                    //for (int stateIdx = cur_t_s_arc.EndPoint.StateNodeSet.Count; stateIdx >= 0; stateIdx--) {
                    //}

                    top_node.Out_T_S_S_NodeList.Add(extendStateNode);
                    allStateNodes.Add(extendStateNode);
                    queue.Enqueue(extendStateNode);
                    ++nodeCount;

                    //if (cur_t_s_arc.ArcType != 32 && cur_t_s_arc.ArcType != 33) {
                    //    IDToNodeDict.Add(extendStateNode.ID, extendStateNode);
                    //}
                    //else {
                    //    tempDNodeList.Add(extendStateNode);
                    //}
                } // end of loop "out_T_S_ArcList"
            }     // end of loop "while"

            // 找出所有可行的状态点(即可以到达虚拟终点的状态点)

            #region //基于回溯
            //T_S_S_NodeList = new List<T_S_S_Node>();
            //foreach (T_S_S_Node note in tempDNodeList) {
            //    int d = note.PrevID;
            //    do {

            //        if (IDToNodeDict.ContainsKey(d)) {
            //            IDToNodeDict[d].Isfeasible = 1;
            //            T_S_S_NodeList.Add(IDToNodeDict[d]);

            //            d = IDToNodeDict[d].PrevID;
            //        }
            //    }
            //    while (d != -1);
            //}
            //T_S_S_NodeList.AddRange(tempDNodeList);
            //T_S_S_NodeList.Sort(T_S_S_Node_AscByTime.nodeAsc);
            //int virODNum = CrewBaseList.Count * 2;
            //int newIDCount = virODNum;
            //foreach (var node in T_S_S_NodeList) {
            //    if (node.ID >= virODNum) {
            //        node.ID = newIDCount;
            //        ++newIDCount;
            //    }
            //}
            //foreach (var node in T_S_S_NodeList) {
            //    if (node.PrevID >= 0) {
            //        node.PrevID = node.PrevNode.ID;
            //    }
            //}
            #endregion

            keepAllFeasibleStateNode(allStateNodes);

            // 根据可行状态点建立时空状态弧
            createT_S_S_Arcs();
        } // end of function CreateT_S_S_Network_db
        /// <summary>
        /// 构建出退乘弧,包括虚拟乘务组出退乘弧,即停驻弧
        /// </summary>
        /// <param name="arcCount"></param>
        private void create_OnAndOff_T_S_Arcs(ref int arcCount)
        {
            #region 创建出退乘弧
            // 只需要一次遍历,因为目的就是把位于基地所在站的stationNode与基地起终点相连
            for (int i = 0; i < T_S_NodeList.Count; i++)
            {
                T_S_Node stationPoint = T_S_NodeList[i];

                T_S_Node baseStartPoint = null;
                T_S_Node baseEndPoint   = null;
                bool     isBaseStation  = false;
                foreach (var crewbase in CrewBaseList)
                {
                    if (stationPoint.StaCode == crewbase.StaCode)
                    {
                        isBaseStation  = true;
                        baseStartPoint = T_S_NodeList[crewbase.VirStartPointID - 1];
                        baseEndPoint   = T_S_NodeList[crewbase.VirEndPointID - 1];
                        break;
                    }
                }
                if (!isBaseStation)
                {
                    continue;
                }
                if (stationPoint.PointType == 1 &&
                    stationPoint.TimeCode < 1440)
                {
                    T_S_Arc t_s_arc = new T_S_Arc();
                    t_s_arc.Init_db(baseStartPoint, stationPoint,
                                    arcCount, 0, stationPoint.RountingID, stationPoint.TrainCode,
                                    baseStartPoint.ID, stationPoint.ID,
                                    stationPoint.StaCode, stationPoint.StaCode,
                                    0, stationPoint.TimeCode,
                                    31);//31——出乘弧

                    T_S_ArcList.Add(t_s_arc);
                    baseStartPoint.Out_T_S_ArcList.Add(t_s_arc);

                    arcCount++;
                }
                if (stationPoint.PointType == 2)
                {
                    T_S_Arc t_s_arc = new T_S_Arc();
                    t_s_arc.ArcType = 32;//32——退乘弧
                    t_s_arc.Init_db(stationPoint, baseEndPoint,
                                    arcCount, 0, 0, stationPoint.TrainCode,
                                    stationPoint.ID, baseEndPoint.ID,
                                    stationPoint.StaCode, stationPoint.StaCode,
                                    stationPoint.TimeCode, 1440,
                                    32);//32——退乘弧
                    if (t_s_arc.StartTimeCode > 1440)
                    {
                        t_s_arc.EndTimeCode = 2880;
                    }

                    T_S_ArcList.Add(t_s_arc);
                    stationPoint.Out_T_S_ArcList.Add(t_s_arc);

                    arcCount++;
                }
            }

            // 创建虚拟停驻弧,即虚拟乘务组出乘弧
            foreach (CrewBase crewbase in CrewBaseList)
            {
                T_S_Node startPoint = T_S_NodeList[crewbase.VirStartPointID - 1];
                T_S_Node endPoint   = T_S_NodeList[crewbase.VirEndPointID - 1];

                T_S_Arc t_s_arc = new T_S_Arc();
                t_s_arc.Init_db(startPoint, endPoint,
                                arcCount, 0, 0, "",
                                crewbase.VirStartPointID, crewbase.VirEndPointID,
                                crewbase.StaCode, crewbase.StaCode,
                                0, 1440, //若是两天会有些变化
                                33);     //33——虚拟乘务组出退乘弧

                T_S_ArcList.Add(t_s_arc);
                startPoint.Out_T_S_ArcList.Add(t_s_arc);
                arcCount++;
            }
            #endregion
        }
        /// <summary>
        /// 创建日间连接弧和夜间连接弧
        /// </summary>
        /// <param name="arcCount"></param>
        /// <param name="minConnTime"></param>
        /// <param name="maxConnTime"></param>
        private void create_Connect_T_S_Arcs(ref int arcCount, int minConnTime, int maxConnTime)
        {
            Dictionary <string, List <T_S_Node> > StationToPointDict = new Dictionary <string, List <T_S_Node> >();

            foreach (var point in T_S_NodeList)
            {
                if (point.PointType == 3 || point.PointType == 4)
                {
                    continue;
                }

                if (!StationToPointDict.ContainsKey(point.StaCode))
                {
                    StationToPointDict.Add(point.StaCode, new List <T_S_Node>());
                }
                StationToPointDict[point.StaCode].Add(point);
            }

            foreach (var pointset in StationToPointDict.Values)
            {
                pointset.Sort(T_S_Node_AscByTime.pointAsc);

                for (int i = 0; i < pointset.Count; i++)
                {
                    T_S_Node startPoint = pointset[i];
                    if (startPoint.PointType == 1)
                    {
                        continue; // 连接弧的起点必须是到达点
                    }

                    for (int j = i + 1; j < pointset.Count; j++)
                    {
                        // 因为排序了,所以后面的node j必然不早于前面的node i,所以可以直接 i + 1
                        T_S_Node endPoint = pointset[j];
                        if (endPoint.PointType == 2)
                        {
                            continue; // 连接弧的终点必须是出发点
                        }

                        int len = endPoint.TimeCode - startPoint.TimeCode;
                        if (len < minConnTime)
                        {
                            continue;
                        }
                        else if (len > maxConnTime)
                        {
                            break;
                        }
                        else
                        {
                            // 不考虑多天的情况,暂且仅考虑1天
                            // 故在此可以直接创建弧
                            T_S_Arc t_s_arc = new T_S_Arc();
                            t_s_arc.Init_db(startPoint, endPoint,
                                            arcCount, startPoint.LineID, startPoint.RountingID, startPoint.TrainCode,
                                            startPoint.ID, endPoint.ID,
                                            startPoint.StaCode, endPoint.StaCode,
                                            startPoint.TimeCode, endPoint.TimeCode,
                                            21);//21——日间连接弧

                            T_S_ArcList.Add(t_s_arc);
                            startPoint.Out_T_S_ArcList.Add(t_s_arc);

                            arcCount++;
                        }
                    }
                }
            }
        }
        public void LoadData_csv(int Days,
                                 string timetableFile,
                                 string crewbaseFile,
                                 string crewFile,
                                 string stationFile)
        {
            string f1 = timetableFile;
            string f2 = crewbaseFile;
            string f3 = crewFile;
            string f4 = stationFile;

            int j;

            string[]     str = new string[7];
            StreamReader csv = new StreamReader(f1, Encoding.Default);
            string       row = csv.ReadLine();

            row = csv.ReadLine();
            //Dictionary<string, bool> StationMap = new Dictionary<string, bool>();
            LineList     = new List <Line>();
            T_S_NodeList = new List <T_S_Node>();

            while (row != null)
            {
                str = row.Split(',');
                Line line = new Line();
                line.ID            = Convert.ToInt32(str[0]);
                line.LineID        = Convert.ToInt32(str[0]);
                line.TrainCode     = Convert.ToString(str[1]);
                line.RountingID    = Convert.ToInt32(str[6]);
                line.DepStaCode    = Convert.ToString(str[2]);
                line.DepTimeCode   = Convert.ToInt32(str[4]);
                line.ArrStaCode    = Convert.ToString(str[3]);
                line.ArrTimeCode   = Convert.ToInt32(str[5]);
                line.LagMultiplier = 0.0;
                line.NumSelected   = 0;
                LineList.Add(line);

                for (j = 0; j < Days; j++)
                {
                    T_S_Node t_s_node1 = new T_S_Node();
                    t_s_node1.ID         = (Convert.ToInt32(str[0]) * 2 - 1);
                    t_s_node1.LineID     = Convert.ToInt32(str[0]);
                    t_s_node1.RountingID = Convert.ToInt32(str[6]);
                    t_s_node1.TrainCode  = Convert.ToString(str[1]);
                    t_s_node1.StaCode    = Convert.ToString(str[2]);
                    t_s_node1.TimeCode   = Convert.ToInt32(str[4]) + 1440 * j;
                    t_s_node1.PointType  = 1;//1——始发点,2——终到点
                    T_S_NodeList.Add(t_s_node1);

                    T_S_Node t_s_node2 = new T_S_Node();
                    t_s_node2.ID         = (Convert.ToInt32(str[0]) * 2);
                    t_s_node2.LineID     = Convert.ToInt32(str[0]);
                    t_s_node2.RountingID = Convert.ToInt32(str[6]);
                    t_s_node2.TrainCode  = Convert.ToString(str[1]);
                    t_s_node2.StaCode    = Convert.ToString(str[3]);
                    t_s_node2.TimeCode   = Convert.ToInt32(str[5]) + 1440 * j;
                    t_s_node2.PointType  = 2;//1——始发点,2——终到点
                    T_S_NodeList.Add(t_s_node2);

                    row = csv.ReadLine();
                }
            }
            csv.Close();

            //CrewBase
            CrewBaseList = new List <CrewBase>();

            csv = new StreamReader(f2, Encoding.Default);
            row = csv.ReadLine();
            row = csv.ReadLine();
            while (row != null)
            {
                str = row.Split(',');

                #region 录入虚拟起终点
                T_S_Node t_s_node1 = new T_S_Node();
                t_s_node1.ID         = T_S_NodeList.Count + 1;
                t_s_node1.LineID     = 0;
                t_s_node1.RountingID = 0;
                t_s_node1.TrainCode  = "";
                t_s_node1.StaCode    = Convert.ToString(str[1]);
                t_s_node1.TimeCode   = 0;
                t_s_node1.PointType  = 3;//1——始发点,2——终到点,3——虚拟起点

                T_S_NodeList.Add(t_s_node1);
                base_start_pointList.Add(t_s_node1);

                T_S_Node t_s_node2 = new T_S_Node();
                t_s_node2.ID         = T_S_NodeList.Count + 1;
                t_s_node2.LineID     = 0;
                t_s_node2.RountingID = 0;
                t_s_node2.TrainCode  = "";
                t_s_node2.StaCode    = Convert.ToString(str[1]);
                t_s_node2.TimeCode   = 0;
                t_s_node2.PointType  = 4;//1——始发点,2——终到点,4——虚拟终点

                T_S_NodeList.Add(t_s_node2);
                base_end_pointList.Add(t_s_node2);
                #endregion

                CrewBase crewbase = new CrewBase();
                crewbase.ID              = Convert.ToInt32(str[0]);
                crewbase.StaCode         = Convert.ToString(str[1]);
                crewbase.PhyCrewCapacity = Convert.ToInt32(str[2]);
                crewbase.VirCrewCapacity = Convert.ToInt32(str[3]);
                crewbase.VirStartPointID = T_S_NodeList.Count - 1;
                crewbase.VirEndPointID   = T_S_NodeList.Count;
                //crewbase.VirStartPointID = Convert.ToInt32(Dt.Rows[i]["时空网起点标号"]);
                //crewbase.VirEndPointID = Convert.ToInt32(Dt.Rows[i]["时空网终点标号"]);
                crewbase.OIDinTSS = Convert.ToInt32(str[4]);
                crewbase.DIDinTSS = Convert.ToInt32(str[5]);
                CrewBaseList.Add(crewbase);

                if (!BaseStationToODIDDict.ContainsKey(crewbase.StaCode))
                {
                    BaseStationToODIDDict.Add(crewbase.StaCode, new int[2] {
                        crewbase.OIDinTSS, crewbase.DIDinTSS
                    });
                }
                else
                {
                    throw new Exception("读取基地数据错误!!");
                }

                row = csv.ReadLine();
            }
            csv.Close();

            //Crew
            csv = new StreamReader(f3, Encoding.Default);
            row = csv.ReadLine();

            CrewList = new List <Crew>();
            while (!csv.EndOfStream)
            {
                row = csv.ReadLine();
                str = row.Split(',');

                Crew crew = new Crew();
                crew.ID         = Convert.ToInt32(str[0]);
                crew.OutCost    = Convert.ToDouble(str[1]);
                crew.RemainCost = Convert.ToDouble(str[2]);
                CrewList.Add(crew);
            }


            //station
            StationList = new List <Station>();
            csv         = new StreamReader(f4, Encoding.Default);
            row         = csv.ReadLine();
            row         = csv.ReadLine();
            while (row != null)
            {
                str = row.Split(',');
                Station station = new Station();

                station.ID         = Convert.ToInt32(str[0]);
                station.StaCode    = str[1];
                station.ReMainCrew = Convert.ToInt32(str[2]);
                StationList.Add(station);
                row = csv.ReadLine();
            }
        }