您的位置:首页 > 其它

AOE关键路径

2016-08-25 13:38 337 查看


AOE网上的关键路径




Time Limit: 1000ms   Memory limit: 65536K  有疑问?点这里^_^



题目描述

    一个无环的有向图称为无环图(Directed
Acyclic Graph),简称DAG图。 
    AOE(Activity
On Edge)网:顾名思义,用边表示活动的网,当然它也是DAG。与AOV不同,活动都表示在了边上,如下图所示:

                                     




    如上所示,共有11项活动(11条边),9个事件(9个顶点)。整个工程只有一个开始点和一个完成点。即只有一个入度为零的点(源点)和只有一个出度为零的点(汇点)。
    关键路径:是从开始点到完成点的最长路径的长度。路径的长度是边上活动耗费的时间。如上图所示,1 到2 到 5到7到9是关键路径(关键路径不止一条,请输出字典序最小的),权值的和为18。


输入

    这里有多组数据,保证不超过10组,保证只有一个源点和汇点。输入一个顶点数n(2<=n<=10000),边数m(1<=m
<=50000),接下来m行,输入起点sv,终点ev,权值w(1<=sv,ev<=n,sv
!= ev,1<=w <=20)。数据保证图连通。


输出

    关键路径的权值和,并且从源点输出关键路径上的路径(如果有多条,请输出字典序最小的)。


示例输入

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



示例输出

18
1 2
2 5
5 7
7 9




/*
边-->活动 点-->事件
*/
# include <bits/stdc++.h>
# define MAXN 10010 //最大顶点数
# define MAXM 50010 //最大边数
using namespace std;
struct node
{
int d; //<u,v>之间的距离
int to; //v点
int on;//活动序号
struct node*next;
};
typedef struct node Node;
struct node *ls1[MAXN]; //正向存储图的信息,出边表的表头
struct node *ls2[MAXN]; //逆向存储图的信息,入边表的表头
int Ee[MAXN]; //各事件最早可能开始的时间
int El[MAXN];//各事件的最迟允许开始时间
int e[MAXN]; //各活动最早可能开始的时间等于Ee
int l[MAXN]; //各活动的最迟允许开始时间
int cnt1[MAXN];//统计正向的各个点的入度
int cnt2[MAXN];//统计反向的各个点的出度
int n,m; //n 顶点数 m 边数
void O_TopSort() //正向拓扑求Ee,可以认为是单点求最长路径
{
int i,u,v;
Node*p;
memset(Ee,0,sizeof(Ee));
stack<int>s;
for(i=1;i<=n;i++)
{
if(cnt1[i] == 0)//入度为0的点入栈
s.push(i);
}
while(!s.empty())
{
u = s.top();
s.pop();
p = ls1[u]; //找到从u发出的每条边,将终点v度数减去1
while(p)
{
v = p->to;
cnt1[v]--;
if(cnt1[v] == 0)
s.push(v);
if(Ee[u] + p->d > Ee[v])
Ee[v] = Ee[u] + p->d;
p = p->next;
}
}
}
void R_TopSort() //逆序拓扑
{
int i,u,v;
Node*p;
memset(El,0,sizeof(El));
stack<int> s;
for(i=1;i<=n;i++)
{
El[i] = Ee
;
if(cnt2[i] == 0)
s.push(i);
}
while(!s.empty())
{
u = s.top();
s.pop();
p = ls2[u];
while(p)
{
v = p->to;
if(--cnt2[v] == 0)
s.push(v);
if(El[u] - p->d < El[v])
El[v] = El[u] - p->d;
p = p->next;
}
}
}

int main()
{
int i,u,v,w;
Node*p;
Node*q;
while(cin>>n>>m)
{
memset(cnt1,0,sizeof(cnt1));
memset(cnt2,0,sizeof(cnt2));
for(i=1;i<=n;i++)
{
ls1[i] = NULL;
ls2[i] = NULL;
}
for(i=0;i<m;i++)//输入m条边的信息
{
cin>>u>>v>>w;
/*出边表*/
p = new Node;
p->d = w;
p->to = v;
p->on = i;
cnt1[v]++;
p->next = ls1[u];
ls1[u] = p;
/*入边表*/
q = new Node;
q->d = w;
q->to = u;
q->on = i;
cnt2[u]++;
q->next = ls2[v];
ls2[v] = q;
}
O_TopSort();//源点到汇点的最长距离
cout<<Ee
<<endl;
R_TopSort();
int k,j;
int Min;
int flag;
for(i=1;i<=n;i++)
{
p = ls1[i];
flag = 0;
if(p)
Min = p->to;
while(p)
{
j = p->to;
k = p->on;//取出改点编号
e[k] = Ee[i]; //边<i,j>
l[k] = El[j] - p->d;
if(e[k] == l[k])//为关键活动
{
if(Min > j)
{
Min = j;
}
flag = 1;
}
p = p->next;
}
if(flag)
{
cout<<i<<" "<<Min<<endl;
i = Min - 1;//直接跳转到当前关键路径节点的下一节点
ls1[i] = NULL;//将字典序最小的赋值
}
}
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息