关键路径
关键路径是基于拓扑排序的一种算法,网上有很多介绍,我就不过多介绍了。
关键在于代码,代码写的很魔性,但是我有打注释,可以参考。
关键路径的关键是找出这个活动的最早开始时间和最晚开始时间,当最早和最晚相等时,这就是一个关键点了。把所有关键点连接起来而且联通起点和终点的路径就是关键路径,但是关键路径可能不只有一条。
1 #include<iostream> 2 #include<cstdio> 3 #include<stack> 4 using namespace std; 5 6 int map[1000][1000],in[1000],out[1000]; 7 //map是记录边的权值,in是某一个点的入度数,out是出度数 8 int a[1000][1000],b[1000][1000],in1[1000]; 9 //a和上一篇拓扑排序里的意思一样,b是反着来的,in1是临时变量。 10 int later[1000],size=0,ans[1000]; 11 //later就是最晚的开始时间,size是找到的路径长度,ans是储存路径 12 int N,M,star,end; 13 //N点数,M边数,star开始点,end结束点 14 stack<int> sk1; 15 16 void pt1() 17 { 18 for(int i=size;i>=1;i--){ 19 printf("%d ",ans[i]); 20 } 21 cout<<end; 22 cout<<endl; 23 } 24 25 void DFS(int x) 26 { 27 28 if(x==star)pt1(); //如果找到开始点就结束输出一条关键路径 29 for(int i=1;i<=in[x];i++){ 30 if( later[x]-map[x][b[x][i]]==later[b[x][i]] ){ 31 //关键路径的判断:最晚开始时间减去权值=上一个最晚的开始时间 32 size++; 33 ans[size]=b[x][i]; 34 DFS(b[x][i]); 35 size--; 36 } 37 } 38 } 39 40 void right() 41 { 42 while(!sk1.empty()){ //正这找拓扑序 43 int x=sk1.top(); 44 sk1.pop(); 45 for(int i=1;i<=out[x];i++){ 46 later[ a[x][i] ]=max( later[ a[x][i] ] , later[x]+map[x][a[x][i]] ); 47 //记录最晚开始时间,之前的最晚开始时间和现在的最晚开始时间做比较 48 in1[ a[x][i] ]--; //减去下一个点的入度 49 if(!in1[ a[x][i] ]) //如果下一个点的入度变为0,就入队,等待下次搜 50 sk1.push(a[x][i]); 51 } 52 } 53 } 54 55 void init() 56 { 57 int aa,bb,cc; 58 cin>>N>>M; 59 for(int i=1;i<=M;i++){ 60 scanf("%d%d%d%*c",&aa,&bb,&cc); 61 map[aa][bb]=cc; //记录权值,以为只用来记录权值所以可以当无向边记录 62 map[bb][aa]=cc; 63 in1[bb]++; //在搜索拓扑序的时候减掉用 64 a[aa][++out[aa]]=bb; //aa点的第x个出度是bb 65 b[bb][++in[bb]]=aa; //bb点的第x个入度是aa 66 } 67 for(int i=1;i<=N;i++){ //找起点和结束点 68 if(out[i]==0)end=i; 69 if(in[i]==0)star=i; 70 } 71 sk1.push(star); 72 } 73 74 int main() 75 { 76 init(); //初始化 77 right(); //关键路径,顺便记录later 78 DFS(end); //搜索关键路径 79 system("pause"); 80 return 0; 81 }