题意:给出一个有向图、源点、终点,求出源点到终点的最短路径和比最短路径长度大1的路径条数。
思路:求出最短路径条数和次短路径条数,如果次短路比最短路长度大一,返回最短路径和次短路径的条数和。否则返回最短路径条数。
实现:dist[i][2]表示点i到源点的两条路径长度,cnt[i][2]表计数,用dijstra的贪心思想对状态进行更新,与求最短路不同的是,次短路也需要入队和更新。
状态更新如下:
1.新值小于最短路:更新次短路及计数,更新最短路及计数。(先把次短路更新为最短路状态,然后更新最短路)
2.新值等于最短路:更新最短路计数。
3.新值大于最短路,小于次短路:更新次短路及计数。
4新值等于次短路:更新次短路计数。
code
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<iostream> #include<stdio.h> #include<string.h> #include<queue> using namespace std; #define M 100010 #define N 1010 #define inf 0x3fffffff struct edge{ int to,w,next; }e[M]; int pre[N],dist[N][2],cnt[N][2],b[N][2]; int cnt0,n,m; void add(int a,int b,int w) { e[cnt0].next=pre[a]; e[cnt0].to=b; e[cnt0].w=w; pre[a]=cnt0++; } struct node{ int w,u,flag; bool operator <(const node &x)const { return w>x.w; } }; int dijstra(int start,int end) { priority_queue<node> q; node in; for(int i=1;i<=n;i++){ dist[i][0]=dist[i][1]=inf; cnt[i][0]=cnt[i][1]=0; b[i][0]=b[i][1]=0; } dist[start][0]=0; cnt[start][0]=1; in.w=0;in.u=start;in.flag=0; q.push(in); while(!q.empty()) { int u=q.top().u; int flag=q.top().flag; q.pop(); if(b[u][flag])continue; b[u][flag]=1; for(int edg=pre[u];edg!=0;edg=e[edg].next) { int v=e[edg].to;int w=dist[u][flag]+e[edg].w; if(dist[v][0]>w) { if(dist[v][0]!=inf) { dist[v][1]=dist[v][0]; cnt[v][1]=cnt[v][0]; in.w=dist[v][1]; in.flag=1; in.u=v; q.push(in); } dist[v][0]=w; cnt[v][0]=cnt[u][flag]; in.w=dist[v][0]; in.u=v; in.flag=0; q.push(in); } else if(dist[v][0]==w) { cnt[v][0]+=cnt[u][flag]; } else if(dist[v][1]>w) { dist[v][1]=w; cnt[v][1]=cnt[u][flag]; in.w=dist[v][1]; in.flag=1; in.u=v; q.push(in); } else if(dist[v][1]==w) { cnt[v][1]+=cnt[u][flag]; } } } if(dist[end][0]==dist[end][1]-1)return cnt[end][0]+cnt[end][1]; else return cnt[end][0]; } int main() { int ca; scanf("%d",&ca); while(ca--) { cnt0=1; memset(pre,0,sizeof(pre)); scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { int a,b,w; scanf("%d%d%d",&a,&b,&w); add(a,b,w); } int start,end; scanf("%d%d",&start,&end); printf("%d\n",dijstra(start,end)); //for(int i=1;i<=n;i++) //cout<<cnt[i][0]<<":"<<dist[i][0]<<endl; } return 0; }