这个题真的是卡了我一天之久。。。倒并不是说它难。有一个地方一直没注意到结果一直wa。。。恶心的我都差点放弃了。。。好在最后改出来。。。这题懂得方法之后并不难。。就只是一个简单地Dijkstra求最短路问题。
题意:给出一些点和一些路径,让你找到倒数第二条最短路径。
分析:要是找到最短路径就好办了,直接无脑套用bellman-Ford或者Dijkstra就可以了,但题目让求次最短路径。想一想。次最短路径不就和最短路径一样么。无非就是再加一个数组,然后求最短路径的过程中顺便维护一个次短路径不就好了。好了,那就直接写呗。
唉,这一点就比较坑了。。。因为输入的路径没有负数,所以我一上来想到的是spfa算法。。。结果TL了。。。。。然后又换的Dijkstra,但是大佬们都说spfa可以过。。。反正用Dijstra过了。。而且这个算法还比spfa稳定。所以就不管了吧。直接上代码:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<vector> using namespace std; const int maxed=5000+10; #define INF 0x3f3f3f3f typedef pair<int,int> P;//这个地方我采用的是邻接表法来储存的这些点和权值 struct Node { int en,val; }; int n,r,d[maxed],d2[maxed];//d数组表示最短路径数组,d2数组表示次最短路径数组 vector<Node> ve[maxed]; int main() { void slove(int); scanf("%d%d",&n,&r); int a,b,c; for(int i=0;i<r;i++){ scanf("%d%d%d",&a,&b,&c); Node n; n.en=b; n.val=c; ve[a].push_back(n); n.en=a; ve[b].push_back(n); } slove(1); printf("%d",d2[n]); return 0; } void slove(int s) { memset(d,INF,sizeof(d)); memset(d2,INF,sizeof(d2)); d[s]=0; priority_queue<P,vector<P>,greater<P> > pq; pq.push(P(d[s],s)); while(!(pq.empty())){ P p=pq.top(); pq.pop(); if(d2[p.second]<p.first) continue; for(int i=0;i<ve[p.second].size();i++){ Node n=ve[p.second][i]; int dd=p.first+n.val;//这个地方就是让我一直wa的地方。。一开始写的dd=d[p.second]+n.val,结果一直wa。。后来终于反应过来,才意识到自己好蠢。。。这个题是要维护的次短路径!!所以这个地方并不一定要求是到某个点的最小路径。还有上边那个减小循环的地方,也是只用判断d2数组就行了。别的地方就只是一个普通的算法了。 if(d[n.en]>dd){ swap(dd,d[n.en]); pq.push(P(d[n.en],n.en)); } if(dd>d[n.en]&&dd<d2[n.en]){ d2[n.en]=dd; pq.push(P(d2[n.en],n.en)); } } } }