拓扑排序
又叫topsort,对于一个oi选手来说。会用就行了(滑稽)
从一个点发出的边数叫做这个点的出度,而一个点被边指向的边的个数就叫做在这个点的入度。
将入读为0的点暂存,then将以这类点作为起点的边删除,相连的点入读-1,然后再将修改后入度为0的点暂存,重复此过程。(本人十分的蒟蒻,所以具体的拓扑排序过程只能大家去问度娘去了)
如果没有入度为0的点,但还有些点没有被遍历到,这就说明存在环。
这里为什么没有说明用什么数据结构储存入度为0的点呢?其实用什么都可以,先后顺序的什么都不重要(题目没有要求的话)
比如就是让你求一个拓扑序的话(配有spical judge),用什么都可以。
当然,有可能为了便于检查。题目会让你输出字典序最小的拓扑序,这时候就要用到堆。每次取出一个字典序最小的就行了。
哪拓扑排序有什么作用呢
举一个具体的例子。大家小学时都做过怎么安排泡茶才能让客人最快地喝上茶
有一系列的准备活动,而且有什么活动必须在什么活动开始之前完成。花费多少时间
我们将活动看成点,先后顺序看成有向边,花费的时间则看成有向边上的权值。
就将问题转化成了求出关键路径的长度
题目
最长路
裸的的拓扑排序,只不过起点和终点固定了。(预处理时可能会有坑)
#include<iostream>
#include<algorithm>
#include<vector>
#include<stack>
using namespace std;
vector<int>way[10600];
vector<int>price[1600];
int du[1600];
stack<int> s;
int dis[1600];
int main()
{
cin.sync_with_stdio(false);
int n,m;
cin>>n>>m;
int p1,p2,v;
for(int i=1;i<=n;i++)
dis[n]=-0x7fffffff;
dis[1]=0;
for(int i=1;i<=m;i++)
{
cin>>p1>>p2>>v;
if(p1>p2)
swap(p1,p2);
way[p1].push_back(p2);
price[p1].push_back(v);
du[p2]++;
}
for(int i=2;i<=n;i++)
if(!du[i])
s.push(i);
int pass;
while(!s.empty())
{
pass=s.top();
s.pop();
int siz=way[pass].size();
for(int i=0;i<siz;i++)
{
du[way[pass][i]]--;
if(du[way[pass][i]]==0)
{
s.push(way[pass][i]);
}
}
}
s.push(1);
while(!s.empty())
{
pass=s.top();
s.pop();
int siz=way[pass].size();
for(int i=0;i<siz;i++)
{
dis[way[pass][i]]=max(dis[way[pass][i]],dis[pass]+price[pass][i]);
du[way[pass][i]]--;
if(du[way[pass][i]]==0)
{
s.push(way[pass][i]);
}
}
}
if(dis[n]!=-0x7fffffff)
cout<<dis[n];
else
cout<<"-1";
}