题目:
次短路计数问题,在更新最短路的同时分类成比最短路短、长于最短路而短于次短路、比次短路长三种情况讨论一下,更新次短路;
然而其实不必被“同时”限制,否则就容易像我一开始一样写挂...
像拆点一样把最短路和次短路完全分开,放进 dijkstra 的优先队列里,真是巧妙;
还要注意一点是直接更新最短路之后要把它的次短路也加进优先队列里,因为次短路同时也被更新了。
代码如下:
#include#include #include #include using namespace std;int const maxn=1005,maxm=10005;int T,n,m,head[maxn],ct,dis[maxn][3],f[maxn][3],s,t;bool vis[maxn][3];struct N{ int to,next,w; N(int t=0,int n=0,int w=0):to(t),next(n),w(w) {}}edge[maxm];struct P{ int bh,d,fl; P(int b=0,int d=0,int f=0):bh(b),d(d),fl(f) {} bool operator < (const P &y) const { return d>y.d;//priority_queue是从大到小排序 }};priority_queue q;void dijkstra(){ while(q.size())q.pop(); memset(vis,0,sizeof vis); memset(f,0,sizeof f); memset(dis,0x3f,sizeof dis); dis[s][0]=0; f[s][0]=1; q.push(P(s,0,0)); while(q.size()) { int x=q.top().bh,d=q.top().d,fl=q.top().fl; q.pop(); if(vis[x][fl])continue; vis[x][fl]=1; for(int i=head[x];i;i=edge[i].next) { int u=edge[i].to,w=edge[i].w; if(dis[u][0]>d+w) { dis[u][1]=dis[u][0]; f[u][1]=f[u][0]; dis[u][0]=d+w; f[u][0]=f[x][fl]; q.push(P(u,dis[u][0],0)); q.push(P(u,dis[u][1],1));//! } else if(dis[u][0]==d+w) f[u][0]+=f[x][fl]; else if(dis[u][1]>d+w) { dis[u][1]=d+w; f[u][1]=f[x][fl]; q.push(P(u,dis[u][1],1)); } else if(dis[u][1]==d+w) f[u][1]+=f[x][fl]; } }}int main(){ scanf("%d",&T); while(T--) { memset(head,0,sizeof head); ct=0; scanf("%d%d",&n,&m); for(int i=1,x,y,z;i<=m;i++) { scanf("%d%d%d",&x,&y,&z); edge[++ct]=N(y,head[x],z); head[x]=ct; } scanf("%d%d",&s,&t); dijkstra(); if(dis[t][1]==dis[t][0]+1)f[t][0]+=f[t][1]; printf("%d\n",f[t][0]); } return 0;}