时间限制:1000MS 代码长度限制:10KB
题型: 编程题 语言: 不限定
Description
在一个工程项目里,多项工作可以同时进行。
我们可以用有向无环图表述项目流程,把项目中的事件表述为结点,把活动表述成有权值的边。
现在我们已知项目共有n个事件,起点为1,终点为n,m个活动。
请你计算出这个项目的最早完成事件,也就是起点到收点的最长路径。
输入格式
第一行两个整数n和m,代表结点数量和边数量。(1<=n,m<=100)
下面m行,每行3个整数a,b,x,表示点a到点b之间有一条长度为x的有向边。
输出格式
一个整数,起点到终点的最长路径.
输入样例
4 6
1 2 3
1 3 2
1 4 3
2 3 3
2 4 5
3 4 3
输出样例
9
关键路径模板题
代码:
#include <iostream>
#include <vector>
#include <queue>
#include <cstring>
using namespace std;
int n,m; //顶点数 边数
int indegree[30]; //入度数
int topo[30]; //拓扑序列
int arcs[30][30]; //矩阵存图 值为权值
int ve[30]; //事件vi最早发生时间
int vL[30]; // 事件vi最迟发生时间
const int MAX=0x3f3f3f3f;
int CP(int cnt) //关键路径
{
if(cnt<n) return -1; //存在有向环 返回-1
memset(ve,0,sizeof(ve)); //ve,vL初始化
memset(vL,0,sizeof(vL));
for(int i=1;i<=n;i++)
{ //按拓扑次序求每个事件的最早发生时间
int k=topo[i];
for(int j=1;j<=n;j++) //依次更新k所有邻接顶点的ve
{
if(arcs[k][j]!=MAX&&ve[j]<ve[k]+arcs[k][j]) //更新j的ve
ve[j]=ve[k]+arcs[k][j];
}
}
for(int i=1;i<=n;i++) //给每个事件的最迟发生时间vL设置初值vL[n]
vL[i]=ve[n];
for(int i=n;i>=1;i--)
{ //按逆拓扑次序求每个事件的最迟发生时间vL
int k=topo[i];
for(int j=1;j<=n;j++)
{
if(arcs[k][j]!=MAX&&vL[k]>vL[j]-arcs[k][j])
vL[k]=vL[j]-arcs[k][j];
}
}
int ans=0; //路径总长度
for(int i=1;i<=n;i++) //判断每一次是否为关键路径
{
for(int j=1;j<=n;j++)
{
int e=ve[i];
if(arcs[i][j]!=MAX)
{
int L=vL[j]-arcs[i][j];
if(e==L) //如果活动<vi,vj>的最早开始时间和最迟开始时间相等,则为关键路径
ans+=arcs[i][j];
}
}
}
return ans;
}
int main()
{
/****************拓扑排序************************/
int e,s,w,cnt=0;
priority_queue<int,vector<int>,greater<int> > q; //优先队列
memset(indegree,0,sizeof(indegree));//初始化
memset(arcs,0x3f,sizeof(arcs));
cin>>n>>m;
for(int i=1;i<=m;i++)
{
cin>>s>>e>>w;
indegree[e]++;
arcs[s][e]=w;//s---->e e依赖于s
}
for(int i=1;i<=n;i++)
if(!indegree[i]) q.push(i); //入度为0的进队
while(!q.empty())
{
int t=q.top(); //取队首元素
q.pop();
topo[++cnt]=t; //t存进topo序列
for(int i=1;i<=n;i++)
if(arcs[t][i]!=MAX) //t---->i i依赖于t
{
indegree[i]--; //出度-1
if(!indegree[i]) //出度为0的入队
q.push(i);
}
}
/*************************************************/
int ans=CP(cnt);
cout<<ans<<endl;
return 0;
}