分析:
题目大意:给出一个具有N 的顶点,M 条边的图,要求输出点1 到N 的最短路。 考察算法:有向无环图的单源最短路 算法一 根据题目的要求我们可以构建出一个有向图G,然后我们在这个图上一边 SPFA 就可以求出点1 到点N 的最短路。注意这道题目不能使用Dijkstra 算法, 因为我们会发现这个图出现了负权,这使得用贪心算法实现的Dijkstra 算法没 有了用武之地。 时间复杂度:O(kM) 空间复杂度:O(N+M) 期望得分:30 分 算法二 仔细分析一下题目我们可以发现这个有向图G,其实是一个有向无环图。对于 有向无环图我们有一个十分高效方法来求得单源最短路,其基本思想是DP。 具体实现过程可以见下面的附录,那里又十分详细的介绍。 时间复杂度:O(N+M) 空间复杂度:O(N+M) 期望得分:100 分#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn=100005,maxm=2000005,INF=2000000000; int dis[maxn],head[maxn],n,ml,md,cnt=0; struct eadge { int next,to,dist; } e[maxm]; void add(int from,int to,int dist) { e[++cnt].next=head[from]; e[cnt].to=to; e[cnt].dist=dist; head[from]=cnt; } int main() { freopen("jogging.in","r",stdin); freopen("jogging.out","w",stdout); scanf("%d%d%d",&n,&ml,&md); int x,y,z; for(int i=1;i<=ml;i++) { scanf("%d%d%d",&x,&y,&z); if(x<y) add(x,y,z); else add(y,x,z); } for(int i=1;i<=md;i++) { scanf("%d%d%d",&x,&y,&z); if(x<y) add(x,y,-z); else add(y,x,-z); } for(int i=1;i<=n;i++) dis[i]=INF; dis[1]=0; for(int i=1;i<=n;i++) { if(dis[i]!=INF) { for(int j=head[i];j;j=e[j].next) { int to=e[j].to; if(dis[to]>dis[i]+e[j].dist) dis[to]=dis[i]+e[j].dist; } } } printf("%d\n",dis[n]); if(dis[n]<0) printf("YES\n"); else printf("NO\n"); fclose(stdin); fclose(stdout); return 0; } 当然用直接用spfa也是不会错的,但要比上一种算法要慢一点。 关于慢跑问题的说明: 这道题目主要为了考察有向无环图的单源最短路。下面来详细介绍着这种算法: 适用条件和范围: 1) DAG(Directed Acyclic Graph,有向无环图); 2) 边权可正可负。 算法描述: 1) Toposort 2) If Toposort=False Then HALT(Not a DAG) 3) For 拓扑序的每个顶点u do For u的每个邻接点v do Relax(u,v,w); 算法结束后:如有环则输出错误信息;否则dis[i]为s到i的最短距离,pre[i] 为前驱顶点。 算法补充: 此算法时间复杂度O(V+E),时间和编程复杂度低,如遇到符合条件的题目(DAG),推 荐使用。还有,此算法的步骤可以在Toposort中实现,这样即减小了此算法复杂度的一 个系数。 其实这道题目还有许多地方需要注意: 1) 输入数据给出的图并不是有向图,当然更不是有向无环图,我们需要根据题目隐藏 的条件将这个图构建成有向无环图; 2) 题目已经说明一定要从编号小的凉亭跑到编号大的凉亭,这就意味这我们完全不需 要进行拓扑排序,因为数据关系已经具有拓扑关系了。我们只需要从1到N进行DP 即可。