1. 程式人生 > >華為codecraft演算法大賽---尋路

華為codecraft演算法大賽---尋路

華為codecraft演算法大賽—尋路

前言

最近實驗室的師兄師姐們在熱火朝天的筆試(都說難難難),我也要了些題來感受了一下,已然被虐的體無完膚。選擇題考的內容涉及範圍廣,演算法程式設計題對於沒有刷題經驗的我來說就更是難上加難了。看來有必要在學習工作之餘學習學習演算法以及計算機基礎知識了。

翻了上半年參加的程式碼,趁週末整理一下當時的思路以及回顧一下資料結構與演算法。比賽前中期還保持不錯的名次,一直維持在二十名左右以為穩穩三十二強了,結果後期突破不大,最後幾天呼呼的被超過,真是太天真了。後來回想確實方法思路比較死板,一口咬定DFS+剪枝,沒有去嘗試新的演算法如A*,模擬退火演算法等,還有大賽群裡分享說的動態規劃、數模等。

賽題介紹

1 問題定義
給定一個帶權重的有向圖G=(V,E),V為頂點集,E為有向邊集,每一條有向邊均有一個權重。對於給定的頂點s、t,以及V的子集V’,尋找從s到t的不成環有向路徑P,使得P經過V’中所有的頂點(對經過V’中節點的順序不做要求)。
若不存在這樣的有向路徑P,則輸出無解,程式執行時間越短,則視為結果越優;若存在這樣的有向路徑P,則輸出所得到的路徑,路徑的權重越小,則視為結果越優,在輸出路徑權重一樣的前提下,程式執行時間越短,則視為結果越優。
說明:
1)圖中所有權重均為[1,20]內的整數;
2)任一有向邊的起點不等於終點;
3)連線頂點A至頂點B的有向邊可能超過一條,其權重可能一樣,也可能不一樣;
4)該有向圖的頂點不會超過600個,每個頂點出度(以該點為起點的有向邊的數量)不超過8;
5)V’中元素個數不超過50;
6)從s到t的不成環有向路徑P是指,P為由一系列有向邊組成的從s至t的有向連通路徑,且不允許重複經過任一節點;
7)路徑的權重是指所有組成該路徑的所有有向邊的權重之和。

2 輸入與輸出
輸入檔案格式
以兩個.csv 檔案(csv 是以逗號為分隔符的文字檔案)給出輸入資料,一個為圖的資料(G),一個為需要計算的路徑資訊(s,t,V’)。檔案每行以換行符(ASCII’\n’即0x0a)為結尾。

1)圖的資料中,每一行包含如下的資訊:
LinkID,SourceID,DestinationID,Cost
其中,LinkID 為該有向邊的索引,SourceID 為該有向邊的起始頂點的索引,DestinationID為該有向邊的終止頂點的索引,Cost 為該有向邊的權重。頂點與有向邊的索引均從0 開始 編號(不一定連續,但用例保證索引不重複)。
2)路徑資訊中,只有一行如下資料:
SourceID,DestinationID,IncludingSet
其中,SourceID 為該路徑的起點,DestinationID 為該路徑的終點,IncludingSet 表示必須經過的頂點集合V’,其中不同的頂點索引之間用’|’分割。
輸出檔案格式
輸出檔案同樣為一個.csv 檔案。
1)如果該測試用例存在滿足要求的有向路徑P,則按P 經過的有向邊順序,依次輸出有向邊的索引,索引之間用’|’分割;
2)如果該測試用例不存在滿足要求的有向路徑P,則輸出兩個字元NA;
3)只允許輸出最多一條有向路徑。

3.簡單用例說明

賽題思路

我當時第一反應就是最短路徑演算法,但是直接套用過來是肯定不行的,因為最短路徑演算法(dijkstra)是一層一層往外擴,然後利用貪心演算法的思想得到每一層級的最優路徑。二本賽題加了必過點的限制,因此需要對演算法進行改造,為了能得到賽題結果,在一步步改造的過程中發現已經拋棄了貪心演算法思想,最後漸漸的升級深度優先遍歷(DFS)的基本思想,但是記錄每一步遍歷的順序,方便回溯(在找到可行解的基礎上還要考慮最優解)。隨著比賽的進行,賽題資料複雜度的增加,回溯版DFS不能在有效的時間內得到最優解,甚至不能得到一個可行解。因此我又在該基礎上增加了”剪枝”的思想,就是剪斷一些出度較大的節點的路徑,這樣可以降低複雜度,並且能得到不錯的結果,“剪枝”的尺度與位置其實是隨機(缺乏科學性)的,由於是比賽,所以可以通過評分程式去修改演算法擬合賽題資料。也是因為這種小聰明導致我這次比賽前中期效果不錯,後期卻非常乏力。這是應該吸取的教訓,還是應該從演算法本身的有效性入手,那樣才會有真正的提高。

以下是輸入資料以及輸出結果樣例



比賽原始碼

比賽要求的編譯環境是Linux+gcc;為了方便除錯,以下程式碼(已帶詳細註釋)是Windows+Visual Stdio下的,有興趣可以自行轉換,也可以在以下地址下載提交版(包括華為官方提供的編譯指令碼)。

#include "stdafx.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fstream> 
using namespace std;

#define PRINT  printf
#define MAX_RECORD  100
#define MAX_LINE_LEN 4000
#define Error( Str )   FatalError( Str )
#define FatalError( Str )   fprintf( stderr, "%s\n", Str ), exit( 1 )
//鄰接表讀圖,
//前面這些把圖讀進鄰接表,
typedef struct ListNode *Position;//位置
typedef Position List;//連結串列
typedef struct Tbl *Table;//鄰接表
typedef int ElementType;
typedef int Vertex;//頂點
typedef struct VertexTable *VerTable;//例子4個頂點
#define Infinity 65536 //各個頂點初始化
#define NotAVertex -1
#define nowstart 0//當前起點,初始化為0
#define NotFound -1//折半查詢
#define LeftChild(i) (2*(i)+1)//堆排序                         
typedef struct StackRecord *Stack;
#define EmptyTOS -1

//*************************************讀檔案********************************************//

int read_file(char ** const buff, const unsigned int spec, const char * const filename)
{
    FILE *fp = fopen(filename, "r");
    if (fp == NULL)
    {
        PRINT("Fail to open file %s, %s.\n", filename, strerror(errno));
        return 0;
    }
    PRINT("Open file %s OK.\n", filename);

    char line[MAX_LINE_LEN + 2];
    unsigned int cnt = 0;
    while ((cnt < spec) && !feof(fp))
    {
        line[0] = 0;
        fgets(line, MAX_LINE_LEN + 2, fp);
        if (line[0] == 0)   continue;
        buff[cnt] = (char *)malloc(MAX_LINE_LEN + 2);
        strncpy(buff[cnt], line, MAX_LINE_LEN + 2 - 1);
        buff[cnt][4001] = 0;
        cnt++;
    }
    fclose(fp);
    PRINT("There are %d lines in file %s.\n", cnt, filename);
    return cnt;
}

//*************************************基本資料結構********************************************//

struct StackRecord
{
    int Capacity;
    int TopOfStack;
    ElementType *Array;
};
////建立棧
Stack CreateStack(int MaxElements)
{
    Stack S;
    S = (struct StackRecord*)malloc(sizeof(struct StackRecord));
    if (S == NULL)
        FatalError("Out of space!!!");
    S->Array = (int*)malloc(sizeof(ElementType)*MaxElements);
    if (S->Array == NULL)
        FatalError("Out of space!!!");
    S->Capacity = MaxElements;
    S->TopOfStack = EmptyTOS;
    return S;
}
//出棧
void Pop(Stack S)
{
    if (S->TopOfStack == EmptyTOS)
        Error("Empty Stack");
    else
        S->TopOfStack--;
}
//入棧
void Push(ElementType X, Stack S)
{
    if (S->TopOfStack == S->Capacity - 1)
        Error("Full stack");
    else
        S->Array[++S->TopOfStack] = X;
}
//銷燬棧
void DisposeStack(Stack S)
{
    if (S != NULL)
    {
        free(S->Array);
        free(S);
    }
}
ElementType Top(Stack S)
{
    if (S->TopOfStack != EmptyTOS)
    {
        return S->Array[S->TopOfStack];
    }
    else
    {
        Error("Empty Stack");
        return 0;
    }
}
//連結串列,每個儲存了頂點Element,權重Cost,指向下一個的Next;
struct ListNode
{
    ElementType ELement;
    int Cost;
    int Priority;
    int Edge;
    Position Next;
};//0->1,1   Element=1,cost=1;

  //鄰接表
struct Tbl
{
    int TableSize;
    List *TheLists;
};

//頂點表
struct VertexTable
{
    int known;
    int Dist;
    Vertex Path;
};

//*************************************鄰接表初始化******************************************//

Table InitializeTable(int TableSize)
{
    Table T;
    int i;
    T = (struct Tbl*)malloc(sizeof(struct Tbl));
    if (T == NULL)
        FatalError("Out of space!!!");
    T->TableSize = TableSize;
    T->TheLists = (struct ListNode**)malloc(sizeof(List)*T->TableSize);
    for (i = 0;i<T->TableSize;i++)
    {
        T->TheLists[i] = (struct ListNode*)malloc(sizeof(struct ListNode));
        if (T->TheLists[i] == NULL)
            FatalError("Out of space!!!");
        else
            T->TheLists[i]->Next = NULL;
    }
    return T;
}

//*************************************連結串列插入********************************************//

void Insert(int Edge, ElementType Pos, ElementType Key, ElementType Cost, ElementType Priority, Table T)
{
    Position NewCell;
    List L;
    NewCell = (struct ListNode*)malloc(sizeof(struct ListNode));
    if (NewCell == NULL)
        FatalError("Out of space!!!");
    else
    {
        L = T->TheLists[Pos];
        NewCell->Next = L->Next;
        NewCell->Edge = Edge;
        NewCell->ELement = Key;
        NewCell->Cost = Cost;
        NewCell->Priority = Priority;
        L->Next = NewCell;
    }
}

//*************************************頂點表初始化*****************************************//

VerTable InitialWeighted(Vertex Start, VerTable V, int NumVertex)//V為頂點集合,每隔頂點有三種標記
{
    int i;
    V = (struct VertexTable*)malloc(sizeof(struct VertexTable)*NumVertex);
    for (i = 0;i<NumVertex;i++)
    {
        V[i].known = 0;
        V[i].Dist = 0;
        V[i].Path = NotAVertex;
    }
    V[Start].Dist = 0;
    return V;
}

//*************************************二分查詢********************************************//

int BinarySearch(const ElementType A[], ElementType X, int N)
{
    int Low, Mid, High;
    Low = 0;High = N - 1;
    while (Low <= High)
    {
        Mid = (Low + High) / 2;
        if (A[Mid]<X)
            Low = Mid + 1;
        else
            if (A[Mid]>X)
                High = Mid - 1;
            else
                return Mid;
    }
    return NotFound;
}

void MakeEmpty(List L)
{
    Position P, Tmp;
    P = L->Next;
    L->Next = NULL;
    while (P != NULL)
    {
        Tmp = P->Next;
        free(P);
        P = Tmp;
    }
}
void Disposable(Table T)
{
    int i;
    for (i = 0;i<T->TableSize;i++)
    {
        MakeEmpty(T->TheLists[i]);
    }
    free(T->TheLists);
    free(T);
}

//*************************************堆排序********************************************//

void PercDown(ElementType A[], int i, int N)
{
    int Child;
    ElementType Tmp;
    for (Tmp = A[i];LeftChild(i)<N;i = Child)
    {
        Child = LeftChild(i);
        if (Child != N - 1 && A[Child + 1]>A[Child])
            Child++;
        if (Tmp<A[Child])
            A[i] = A[Child];
        else
            break;
    }
    A[i] = Tmp;
}
void Swap(int *a, int *b)
{
    int temp;
    temp = *a;
    *a = *b;
    *b = temp;
}
void Heapsort(ElementType A[], int N)
{
    int i;
    for (i = N / 2;i >= 0;i--)
        PercDown(A, i, N);
    for (i = N - 1;i>0;i--)
    {
        Swap(&A[0], &A[i]);
        PercDown(A, 0, i);
    }
}

//*************************************列印路徑********************************************//

void PrintPath(Vertex Ver, VerTable V, int C[])
{
    if (V[Ver].Path != NotAVertex)
    {
        PrintPath(V[Ver].Path, V, C);
        printf("->");
    }
    printf("%d", C[Ver]);
}

//************************************輸出邊編號*******************************************//

int find_route(int stop, Table T, VerTable V)
{
    Position Tmp;
    int result = -1;
    Tmp = T->TheLists[V[stop].Path]->Next;//
    while (Tmp != NULL)
    {
        if (Tmp->ELement == stop) { result = Tmp->Edge;break; }
        Tmp = Tmp->Next;
    }
    return result;
}

///*************************************重複邊處理****************************************//

Position FindPrevious(ElementType X, List L)
{
    Position P;

    P = L;
    while (P->Next != NULL && P->Next->ELement != X)
        P = P->Next;

    return P;
}
int IsLast(Position P, List L)
{
    return P->Next == NULL;
}

void Delete(ElementType X, List L)
{
    Position P, TmpCell;

    P = FindPrevious(X, L);

    if (!IsLast(P, L))  /* Assumption of header use */
    {                      /* X is found; delete it */
        TmpCell = P->Next;
        P->Next = TmpCell->Next;  /* Bypass deleted cell */
        free(TmpCell);
    }
}
Position Find(ElementType X, List L)
{
    Position P;
          P = L->Next;
          while (P != NULL && P->ELement != X)
           P = P->Next;
          return P;
}

///*******************************/自定義查詢下一頂點的演算法*************************************//

int find_start(VerTable V, Table T, ElementType demand[], int start_now, int known_p, int end, Stack S, int N)
{
    //傳入的引數分別為:頂點表(konwn,dis,path)、優先點集、當前遍歷起點
    //返回值為下一個起點索引TempV,以及特徵點入棧
    Position tmp;
    int min = Infinity;//普通點最小權值
    int min_sp = Infinity;//優先點最小權值
    int count_sp = 0;//優先點計數(用於判斷特徵點)
    int count_normal = 0;//普通點計數
    int normal[8] = { 0 };//普通點陣列(暫存)
    int special[8] = { 0 };//優先點陣列(暫存)
    Vertex TempV = -1;//開始標記
    int flag = 0;//終點標記
                 //TMP = T->TheLists[start_now];
    tmp = T->TheLists[start_now]->Next;
    while (tmp != NULL) //0->3->1->NULL  還有鄰接點且未到達過
    {
        if (V[tmp->ELement].known != 1) {
            if (tmp->Priority == 1)//如果該頂點是優先點
            {
                count_sp++;//當前層級優先點數+1
                if (tmp->Cost < min_sp) //當前點權值更小
                {
                    if (count_sp > 1)
                    {
                        special[count_sp - 2] = TempV;
                        V[TempV].Dist = 0;
                    }
                    min_sp = tmp->Cost;//更新min_sp                   
                    TempV = tmp->ELement;//返回值
                    V[TempV].Dist = V[start_now].Dist + tmp->Cost;
                }
                else
                {
                    if (count_sp > 1)
                    {
                        special[count_sp - 2] = tmp->ELement;;
                    }
                }
            }
            else if (tmp->ELement == end)//如果該頂點是終點
            {
                flag = 1;//表明這一輪有終點,但暫時不作處理
                V[end].Dist = V[start_now].Dist + tmp->Cost;
                V[end].Path = start_now;
            }
            else //如果該頂點是普通點
            {
                count_normal++;//普通點計數
                normal[count_normal - 1] = tmp->ELement;//普通點暫存
                if (count_sp == 0 && tmp->Cost < min)//(1.有普通點沒有終點沒有優先點2.有普通點有終點沒有優先點)
                {
                    min = tmp->Cost;//更新min
                    V[TempV].Dist = 0;
                    TempV = tmp->ELement;//返回值  
                    V[TempV].Dist = V[start_now].Dist + tmp->Cost;
                }
            }
        }
        tmp = tmp->Next;
    }
    ///////////*************************LOOK***************************///////////////
    if (count_sp == 0) //假如沒有優先點,則把多餘的普通點全部入棧
    {
        for (int i = 0;i < count_normal;i++)
        {
            if (TempV != normal[i])
            {
                Push(normal[i], S);Push(start_now, S);//V[normal[i]].Path = start_now;
            }
        }//普通點分支入棧      
    }
    else//當優先點數>=1時
    {
        if (count_sp == 1)//假如剛好只有一個優先點,那麼普通點入棧,並賦值path
        {
            for (int i = 0;i < count_normal;i++) { Push(normal[i], S); Push(start_now, S); }//V[normal[i]].Path = start_now;
        }
        else//當優先點數大於1時,普通點先全部入棧,然後多餘的優先點入棧
        {
            for (int i = 0;i < count_normal;i++) { Push(normal[i], S); Push(start_now, S); } //V[normal[i]].Path = start_now;
            for (int i = 0;i < count_sp - 1;i++) { Push(special[i], S);Push(start_now, S); }//V[special[i]].Path = start_now;
        }
    }
    if (flag == 1 && known_p == N)//已到終點,且這一層沒有優先點了,就要判斷是否已經結束(優先點已全部在路徑中)
    {
        TempV = 10000; //10000結束標誌,到達終點且所有的優先點已在路徑中
    }
    if (TempV == -1) { TempV = -start_now; if (start_now == 0) { TempV = -1000; } }//返回停止點(帶負號,方便處理)
    if (TempV != 10000 && TempV >= 0) { V[TempV].Path = start_now; }
    return TempV;//返回下一起點索引
}

//**************************************核心查詢演算法********************************************//

int DF(VerTable V, Table T, ElementType demand[], Stack S, int N, int start_now, int end, unsigned short *result,int big)
{
    //Vertex Ver, W;//頂點索引
    Position Tmp;
    //int end = 5;//假定一個終點
    int startone=start_now ;//存起點
    int known_p = 0;//記錄已到過的優先點
    int flag = 0;//遍歷過優先點標記
    int min_dist = 10000;
    int ok = 0;
    for (;;)
    {
        if (start_now == 10000)//當前起點為10000,查詢成功
        {
            flag++;//迭代次數
            if (min_dist > V[end].Dist)
            {
                int tmp = end;
                int count = 0;
                while (tmp != startone)
                {
                   result[count] = find_route(tmp, T, V);
                   count++;
                   ok = count;
                   tmp = V[tmp].Path;
                }
                min_dist = V[end].Dist;
            }
            else V[end].Dist = min_dist; 
            if (S->TopOfStack == -1||flag>10) break;
                printf("flag:%d\n",flag);           
                //if (big>7&&big<30)break;
                //if (big>150 && big<200&&flag>7)break;
                //if (big>200 && big<250 && flag>3)break;
                if (big>250&&flag>0)break;
                int pass = Top(S);//獲得特徵點索引 0->1->3                 
                Pop(S);//出棧
                start_now = Top(S);//將當前起點改為棧頂元素        
                int stop = V[end].Path;//繼續回溯
                while (stop != pass)
                {
                    V[stop].known = 0;
                    if (BinarySearch(demand, stop, N) >= 0) { known_p--; }
                    stop = V[stop].Path;
                }
                Pop(S);//出棧 
                /*if (S->TopOfStack != -1) {
                    if (big> 150&&big<200) { Pop(S);Pop(S); }//邊數在
                    if (big> 200 && big<250) { Pop(S);Pop(S);Pop(S);Pop(S); }//邊數在200-250,一次剪斷兩條邊
                    if (big> 250) { Pop(S);Pop(S);Pop(S);Pop(S);Pop(S);Pop(S); }//邊數大於250,一次剪斷三條邊*/
                //剪枝操作
                V[start_now].Path = pass;//出棧起點路徑資訊
                Tmp = T->TheLists[pass]->Next;
                while (Tmp != NULL)
                {
                    if (Tmp->ELement == start_now) { V[start_now].Dist = V[pass].Dist + Tmp->Cost; }
                    Tmp = Tmp->Next;
                }
        }       
        if (start_now < 0 && S->TopOfStack == -1) break; //棧空,則返回無解
        if (start_now <0)//回頭
        {
            int stop = -start_now;//停止點
            if (start_now == -1000) { stop = 0; }//0為停止點的情況
            int pass = Top(S);//獲得特徵點索引 0->1->3                 
            Pop(S);//出棧
            //printf("%d出棧:\n", pass);
            start_now = Top(S);//將當前起點改為棧頂元素            
            while (stop != pass)
            {
                V[stop].known = 0;
                if (BinarySearch(demand, stop, N) >= 0) { known_p--; }
                //printf("%d回撤:\n", stop);
                stop = V[stop].Path;
                //V[stop].Path = NotAVertex;
            }
            Pop(S);//出棧 
            //printf("%d出棧:\n", start_now);
            if (S->TopOfStack != -1) {
                //if (big>150 && big < 200) { Pop(S);Pop(S);}//邊數在150-200之間,一次剪斷一條邊
                if (big> 100&&big<250) { Pop(S);Pop(S);Pop(S);Pop(S); }//邊數在200-250,一次剪斷兩條邊
                if (big> 250) { Pop(S);Pop(S);Pop(S);Pop(S);Pop(S);Pop(S);}//邊數大於250,一次剪斷三條邊
            }//剪枝操作
            V[start_now].Path = pass;//出棧起點路徑資訊
            Tmp = T->TheLists[pass]->Next;
            while (Tmp != NULL)
            {
                if (Tmp->ELement == start_now) { V[start_now].Dist = V[pass].Dist + Tmp->Cost; }
                Tmp = Tmp->Next;
            }
        }
        V[start_now].known = 1;//將當前起點標記為已知
        if (BinarySearch(demand, start_now, N) >= 0) { known_p++; }//記錄到達的優先點數
        start_now = find_start(V, T, demand, start_now, known_p, end, S, N);//按自定義方法找下一個起點
        printf("當前點:%d\n",start_now);
    }
    return ok;
}

//**************************************呼叫演算法********************************************//

void search_route(char *graph[5000], int edge_num, char *condition)//字串陣列(topo),行數,字串(demand)
{
    Table T = InitializeTable(600);//頂點
    VerTable V = NULL;
    Stack S = CreateStack(1000);//建立棧(存分支點)
    unsigned short result[100] = { -1 };//示例中的一個解 
    const int n = edge_num;
    int  N, start_now, end, demand[100] = { -1 }, test[400][4] = { 0 };
    char *save_ptr, *line;//存剩餘的
    for (int i = 0;i<n;i++)//test初始化
    {
        char *hello = graph[i];
        char *p, *token;
        int j = 0;
        for (p = hello; ; p = NULL, j++)
        {
            token = strtok_s(p, ",", &save_ptr);
            if (NULL == token)   break;
            test[i][j] = atoi(token);
        }
    }
    start_now = atoi(strtok_s(condition, ",", &save_ptr));//起點
    printf("start_now=%d \n", start_now);
    end = atoi(strtok_s(NULL, ",", &save_ptr));//終點
    printf("end=%d \n", end);
    line = strtok_s(NULL, ",", &save_ptr);//優先點字串
    printf("special_line=%s \n", line);
    char *get, *token;
    save_ptr = NULL;
    int d_count = 0;
    for (get = line; ; get = NULL, d_count++)
    {
        token = strtok_s(get, "|", &save_ptr);
        if (NULL == token)   break;
        demand[d_count] = atoi(token);
        // printf("demand[%d]=%d \n",d_count,demand[d_count]);
    }
    N = d_count;
    int Sort[400 * 2] = { -1 }, Max, *C, p = 0, Stemp, Etemp, *Fdemand;
    for (int i = 0; i < n; i++)
    {
        Sort[2 * i] = test[i][1];
        Sort[2 * i + 1] = test[i][2];
    }//把起點和終點包含的點都算進來
    Heapsort(Sort, n * 2);//對頂點進行排序
    Max = Sort[2 * n - 1];
    C = (int*)malloc(sizeof(int)*(Max + 1));
    if (NULL == C)
    {
        FatalError("Out of space!!!");
    }
    for (int i = 0;i<2 * n;i++)
    {
        if (Sort[i] != Sort[i + 1])
        {
            C[p] = Sort[i];
            p++;
        }
    }
    printf("edge_num=%d \n", n);
    printf("point_num=%d \n", p);
    printf("special_num=%d \n", N);
    Fdemand = (int*)malloc(sizeof(int)*(N));;
    for (int i = 0;i<N;i++)
    {
        Stemp = BinarySearch(C, demand[i], p);
        Fdemand[i] = Stemp;
    }
    Heapsort(Fdemand, N);
    Position Pos,L;
    /*for (int j = 0;j<n;j++)//鄰接表插入
    {
        Stemp = BinarySearch(C, test[j][1], p);
        Etemp = BinarySearch(C, test[j][2], p);
        if (BinarySearch(Fdemand, Etemp, N) >= 0)
        {
            Insert(test[j][0], Stemp, Etemp, test[j][3], 1, T);//start,stop,cost,List,把3必過點插入
            T->TheLists[Stemp]->ELement++;//有幾個優先順序的點
        }
        else
        {
            Insert(test[j][0], Stemp, Etemp, test[j][3], 0, T);//start,stop,cost,List,把3必過點插入
            T->TheLists[Stemp]->ELement++;//有幾個優先順序的點
        }
    }*/
////////////////////////////////////////////////////
    for (int j = 0;j<n;j++)
    {
        Stemp = BinarySearch(C, test[j][1], p);
        Etemp = BinarySearch(C, test[j][2], p);
        if (BinarySearch(Fdemand, Etemp, N) >= 0)
        {
            L = T->TheLists[Stemp];
            Pos = Find(Etemp, L);
            if (NULL == Pos)
            {
                Insert(test[j][0], Stemp, Etemp, test[j][3], 1, T);//start,stop,cost,List,把3必過點插入
                T->TheLists[Stemp]->ELement++;//有幾個優先順序的點
            }
            else
            {
                if (Pos->Cost > test[j][3])
                {
                    Delete(Pos->ELement, L);
                    T->TheLists[Stemp]->ELement--;//有幾個優先順序的點
                    Insert(test[j][0], Stemp, Etemp, test[j][3], 1, T);
                    T->TheLists[Stemp]->ELement++;//有幾個優先順序的點
                }
            }
        }
        else
        {
            L = T->TheLists[Stemp];
            Pos = Find(Etemp, L);
            if (NULL == Pos)
            {
                Insert(test[j][0], Stemp, Etemp, test[j][3], 0, T);
                T->TheLists[Stemp]->ELement++;//有幾個優先順序的點
            }
            else
            {
                if (Pos->Cost > test[j][3])
                {
                    Delete(Pos->ELement, L);
                    T->TheLists[Stemp]->ELement--;//有幾個優先順序的點
                    Insert(test[j][0], Stemp, Etemp, test[j][3], 0, T);//start,stop,cost,List,把3必過點插入
                    T->TheLists[Stemp]->ELement++;//有幾個優先順序的點
                }
            }

        }
    }

////////////////////////////////////////////////////
    start_now = BinarySearch(C, start_now, p);
    end = BinarySearch(C, end, p);
    V = InitialWeighted(0, V, n);
    int route = DF(V, T, Fdemand, S, N, start_now, end, result,n);//最短路徑D演算法     
    int tmp = end;
    int result_count = route;//解的個數
    if (route == 0) { printf("NA\n"); }
    else
    {
        /*if (N>=16) {
        result_count =0;
        while (tmp != start_now)
        {
            result[result_count] = find_route(tmp, T, V);
            result_count++;
            tmp = V[tmp].Path;
        }
        }*/
        PrintPath(end, V, C);
        printf(" COST=%4d\n", V[end].Dist);
        for (int i = result_count - 1;i >= 0;i--)
        {
            printf("%d | ", result[i]);
            //record_result(result[i]);
        }
        printf("\n");
    }
    Disposable(T);
    DisposeStack(S);
    free(V);
    free(C);
    free(Fdemand);
    //record_result(result[i]);
}

int main()
{
    char *topo[5000];
    int edge_num;
    char *demand;
    int demand_num;
    edge_num = read_file(topo, 5000, "topo.csv");
    demand_num = read_file(&demand, 1, "demand.csv");
    search_route(topo, edge_num, demand);
    getchar();
    return 0;
}