1. 程式人生 > >資料結構實驗之圖論十一:AOE網上的關鍵路徑

資料結構實驗之圖論十一:AOE網上的關鍵路徑

/** 演算法分析,先用拓撲排序判斷是否有迴路,然後在算出每個活動的最早開始時間
*** 最晚開始時間然後在算出關鍵路徑***/
#include <bits/stdc++.h>
using namespace std;
class Edge
{
public:
    int from,to, data;
    Edge(int x=0,int y=0,int z=0) : from(x), to(y), data(z) {}
};

class Vertex
{
public:
    int id;
    int ans;  /// 節點入度
    vector<int >next;
};

class Map
{
private:
    int n;
    bool visit[10000+10] ;
    vector<Edge> E;
    vector<int> p; /// 存放拓撲排序序列
    int ve[10000+10];/// 頂點活動發生的最早發生時間
    int vl[10000+10];/// 定點活動發生的最晚時間
public:
    Vertex G[10000+10];
    void Init(int n)
    {
        this->n = n;
        E.clear();
        p.clear();
        for(int i = 0 ; i<= n; i++)
        {
            ve[i] = - 1 ;
            vl[i] = INT_MAX;
            visit[i] = false;
            G[i].ans = 0 ;
            G[i].next.clear();
            G[i].id = i;
        }
    }
    void Add_Edge(int x,int y,int z=0)
    {
        E.push_back(Edge(x,y,z));
        int len = E.size();
        G[x].next.push_back(len - 1 ) ;
        G[y].ans++;
    }
    bool TopSort()
    {
        queue<int> L;
        for(int i = 1; i<=n ; i++) /// 將入度為零的點進棧
        {
            if(G[i].ans == 0)
            {
                L.push(G[i].id);
            }
        }
        while(!L.empty())
        {
            int t = L.front();
            L.pop();
            p.push_back(t);
            visit[t] = true;
            int len = G[t].next.size();
            for(int i = 0 ; i<len; i++ )  /// 刪邊
            {
                int j =E[G[t].next[i]].to;
                int data = E[G[t].next[i]].data;
                if(visit[j] == false)
                {
                    G[j].ans--;
                    if(G[j].ans == 0)
                    {
                        L.push(j) ;
                    }
                }
            }
        }
        if(p.size() == n)
        {
            return true;
        }
        return false;
    }
    void BFS(int x,int y)/// 利用BFS求得 每個定點的最早開始時間 以及最晚時間
    {
        ve[x] = 0 ;
        memset(visit,false, sizeof(visit)) ;
        queue<int>L;
        stack<Edge> l;/// 利 棧 儲存邊的相對位置
        L.push(x);
        while(!L.empty())
        {
            int t = L.front() ;
            L.pop();
            if(visit[t]== true)
                continue;
            visit[t] = true;
            int len = G[t].next.size();
            for(int i = 0 ; i<len; i++)
            {
                l.push(E[G[t].next[i]]) ;
                int to   = E[G[t].next[i]].to;
                int data = E[G[t].next[i]].data;
                ve[to] = max(ve[to],ve[t] + data);
                L.push(to);
            }
        }
        vl[y] =  ve[y];
        while(!l.empty())
        {
            Edge t  = l.top();
            l.pop();
            int from = t.from;
            int to   = t.to;
            int data = t.data;
            vl[from] = min(vl[from],vl[to]-data);
        }
    }
    void CriticalPath(int x,int y)
    {
        memset(visit,false,sizeof(visit)) ;
        BFS(x,y);
        ///   for(int i = 0 ;)
        /********   確定最終路線  *****/
        p.clear() ;
        p.push_back(x) ;
        int sum = 0 ;
//        for(int i = 1 ;i<= n;i++)
//        {
//            printf("ve[%d] == %d\n",i,ve[i]);
//        }
//        cout<<endl;
//        for(int i = 1 ;i<= n;i++)
//        {
//            printf("vl[%d] == %d\n",i,vl[i]);
//        }
//        printf("關鍵路徑的資料為 : \n");
        queue<int > L;
        L.push(x) ;
        memset(visit,false,sizeof(visit)) ;
        while(!L.empty())
        {
            int t = L.front() ;
            L.pop();
            if(visit[t] == true)
            {
                continue;
            }
            visit[t] = true;
            int len = G[t].next.size();
            int key = INT_MAX;
            bool flag = false;
            int data = -1 ;
            for(int i = 0 ; i<len; i++)
            {
                int to   = E[G[t].next[i]].to;
                int ans  = E[G[t].next[i]].data;
                int from = E[G[t].next[i]].from ;
                //cout<<"from ==     "<<from<<" , to ==     "<<to<<" , data ==    "<<ans<<endl;
               // cout<<"ve[from] == "<<ve[from]<<"  v1[to] == "<<vl[to]<<endl;
                int x = ve[from] , y = vl[to] - ans;
               // cout<<"x = "<<x<<"  , y == "<<y<<endl;
                if(x == y)
                {

                    if(key > to)
                    {
                        key = to ;
                        data = ans;
                    }
                    flag = true;
                }
            }
            if(flag == true)
            {
                //cout<<data<<" ";
                sum += data;
                L.push(key) ;
                p.push_back(key) ;
                t = key;
            }
        }
        cout<<sum<<endl;
        int len = p.size();
        for(int i = 0 ; i<len-1; i++)
        {
            cout<<p[i]<<" "<<p[i+1]<<endl;
        }
    }
};
Map a;
bool b[10000+10] = {false}; /// 源點
bool c[10000+10] = {false}; /// 匯點
int main()
{
    int n,m;
    while(cin>>n>>m)
    {
        a.Init(n);
        memset(b,false,sizeof(b)) ;
        memset(c,false,sizeof(c)) ;
        for(int i = 0 ; i<m; i++)
        {
            int x,y,z;
            cin>>x>>y>>z;
            a.Add_Edge(x,y,z) ;
            b[x] = true;
            c[y] = true;
        }
        int x, y ;
        for(int i = 1 ; i<= n; i++)
        {
            if(b[i] == false)
            {
                y = i;
            }
            if(c[i] == false)
            {
                x = i;
            }
        }
        a.CriticalPath(x,y);
    }
    return 0 ;
}
/**
10 13
1 2 5
1 3 6
2 4 3
3 4 6
3 5 3
4 5 3
4 6 4
5 7 1
5 8 4
7 9 5
8 9 2
6 10 4
9 10 2

9 11
1 2 6
1 3 4
1 4 5
2 5 1
3 5 1
4 6 2
5 7 9
5 8 7
6 8 4
8 9 4
7 9 2

7 10
1 2 3
1 4 6
1 3 2
2 5 4
2 4 2
3 4 1
3 6 3
4 5 1
5 7 3
6 7 4
****/


/***************************************************
User name: 大鐵棍子醫院銅主任
Result: Accepted
Take time: 104ms
Take Memory: 2048KB
Submit time: 2017-08-23 11:03:37
****************************************************/