1、AOV和AOE網
AOV是指的用頂點(Vertex)表示活動,用邊集表示活動間優先順序的有向圖,圖中不會有環。
AOE是指用帶權的邊集(Edge)表示活動,用頂點表示事件的有向圖,邊權表示 完成活動所需要的時間。AOE網表示一個工程的進行過程,它也不應該有環,一般來說它只有一個源點(入度爲零)和一個匯入點(初度爲零),其實AOV網也可以轉換爲AOE網。
AOE網着重解決的問題有:①工程從開始到結束需要多少時間②工程中哪些分工程是影響全局的。一般來說 第二個問題會轉換到最長路徑。
2、最長路徑
和我們在之前看過的最短路徑不同,最長路徑,一般代表的是那種不能拖延的工程,如何求最長路徑呢?
將所有權值變負,然後用FORD算法算出最小的那個,然後再變正就是了。
3、關鍵路徑
AOE網實際上屬於有向無環圖,下面給出一個求解有向無環圖中最長路徑的方法
首先設置兩組數組,e和l,第一個表示最早開始的時間,第二個表示最遲開始的時間,如果e==l,則說明這個活動是不能拖延的 ,即爲我們所求的關鍵路徑。然後問題來了,怎麼求e和l呢?
事件v1在經過活動a之後到達V2,然而是否立即到達頂點V2,也存在拖延的可能性,所以會出現最早發生和 最遲發生兩種極端情況,某一個事件最遲發生可以認爲下一個事件的最遲開始,設置兩個新的數組Ve和Vl,分別表示其最早開始時間和最遲開始時間:
①對於一個活動,在上一個事件最早發生時開始則會得到最早開始時間,e=Ve;
②對於一個事件,他的最遲發生時間就是上個活動最遲開始時間加上路的權值,即 vl=l+w;
然後對於我們的難題就轉移到求端點的最早開始和最晚開始時間
假設有k個事件,通過相應的活動到達事件J,假設我們已經得到了每個事件的最早發生時間VE,那麼VJ最早發生時間就是各個事件VE+w中的最大值,因爲只有所有事件都發生且經過活動到達之後,J纔會被激活,所以想要獲得VE[J]的正確值,VE[V1]~VE[VK]必須全部都到手 ,通過拓撲排序就可以保證其前驅端點都訪問完畢了,但是不可能通過J去拓撲他的前驅端點,因此可以在訪問他的前驅端點是,就不斷地更新VE[J]。
if(ve[u]+G[u][i].w>ve[j])
{
ve[j]=ve[u]+G[u][i].w;
}
同理,若獲得VJ,那麼1~K的最晚發生時間也可以確定,這時需要保證他的後繼結點都已經被訪問完bool topol()//判斷是否非環
{
queue<int >q;
for(int i=0;i<n;i++)
{
if(inDegree[i]==0)//入度爲零
{
q.push(i);
}
}
while(!q.empty())
{
int u=q.front();
q.pop;
topOrder.push(u);//加入序列
for(int j=0;j<G[u].size();j++)
{
int v=G[u][j].v;
inDegree[v]--;
if(inDegree[v]==0)//入度爲零
{
q.push(v);
}
if(ve[u]+G[u][i].w>ve[j])
{
ve[j]=ve[u]+G[u][i].w;
}
}
}
if(topOrder.size()!=n) return false;
else return true;
}
int CriticalPath()
{
memset(ve,0,sizeof(ve));
if(topol()==false)
{
return -1;
}
fill(vl,vl+n,ve[n-1]);
while(!topOrder.empty())
{
int u = topOrder.top;
topOrder.pop();
for(int i=0;i<G[u].size();i++)
{
int v=G[u][i].v;
if(ve[v]-G[u][i].w<vl[u])//用u的所有後繼點來更新vl[u]
{
vl[u]=vl[v]-G[u][i].w;
}
}
}
for(int u=0;u<n;u++)
{
for(int i=0;i<G[u].size();i++)
{
int v =G[u][i].v,w=G[u][i].w;
int e=ve[u],l=vl[v]-w;
if(e==l)
{
printf("%d->%d",u,v);
}
}
}
return ve[n-1];
}