求次短路什么的最好用Dijkstra,因为每次取最小的,有序使得最后结果。
这题相当纠结。首先的想法是先把起点到其它点的最短距离与最短路径数目算出来,自然就知道S到T最短路的条数。然后枚举每条边(u,v,w),如果S到u的最短路距离+w+v到T的最短距离等于S到T的最短距离+1时,那么肯定满足题意,增加的条数为S到u最短路的路线数*v到T最短路的路线数。但这样会有问题,一条比最短路径长度大一的路径会算很多遍。所以我后面加了一个条件,就是v在最短路的路径上,即S到v与v到T的最短距离和等于S到T的最短距离。这样的话,每条比最短路长一的路径有且仅会算一次。
用SPFA求前面最短路的条数后,一直WA,开始以为是算条数的时候错了。但细想之下,觉得不可能错,后面还是cyx用Dijkstra过了之后,我再用那方法A了之后,然后忽然想到说不定SPFA错的,所以就把SPFA换成Dijkstra就过了。。。细想之后,发现确实有问题。。。解释如注释。。。
#include<stdio.h> #include<iostream> #include<vector> #include<algorithm> #include<string.h> using namespace std; const int maxn=1100; const int maxm=11000; const int maxint=0x3fffffff; struct point { int u,v,w; }p0,p[maxm]; vector<point> e[maxn],e1[maxn]; int n,dist[maxn],dist1[maxn],num[maxn],num1[maxn]; /*void SPFA(int s,int dist[],vector<point> e[],int num[]) { int i,k,q[maxn],head=0,tail=0; bool inq[maxn]; for(i=1;i<=n;i++) dist[i]=maxint,inq[i]=false,num[i]=0; dist[s]=0; q[tail++]=s; num[s]=1; inq[s]=true; while(head!=tail) { i=q[head]; inq[i]=false; head=(head+1)%maxn; for(k=0;k<e[i].size();k++) { if(dist[e[i][k].v]>dist[i]+e[i][k].w) { num[e[i][k].v]=num[i]; dist[e[i][k].v]=dist[i]+e[i][k].w; if(!inq[e[i][k].v]) { inq[e[i][k].v]=true; q[tail]=e[i][k].v; tail=(tail+1)%maxn; } }//这里如果相等,那么后面的路径应该要更新,所以应该要入队,但入队的话后面又会多计算,所以不能简单的处理。应该要用双关键字 else if(dist[e[i][k].v]==dist[i]+e[i][k].w) num[e[i][k].v]+=num[i]; } } }*/ void D(int s,int dist[],vector<point> e[],int num[]) { int ii,i,j,k; bool visit[maxn]; for(i=1;i<=n;i++) dist[i]=maxint,num[i]=0,visit[i]=false; dist[s]=0; num[s]=1; for(i=1;i<=n;i++) { for(k=maxint,ii=-1,j=1;j<=n;j++) if(!visit[j]&&dist[j]<k) { k=dist[j]; ii=j; } if(ii==-1) break; visit[ii]=true; for(j=0;j<e[ii].size();j++) { if(visit[e[ii][j].v]) continue; if(dist[e[ii][j].v]>dist[ii]+e[ii][j].w) { dist[e[ii][j].v]=dist[ii]+e[ii][j].w; num[e[ii][j].v]=num[ii]; } else if(dist[e[ii][j].v]==dist[ii]+e[ii][j].w) num[e[ii][j].v]+=num[ii]; } } } int main() { // freopen("1.in","r",stdin); // freopen("1.out","w+",stdout); int t,m,S,T,i,sum; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); for(i=1;i<=n;i++) e[i].clear(),e1[i].clear(); for(i=1;i<=m;i++) { scanf("%d%d%d",&p0.u,&p0.v,&p0.w); p[i]=p0; e[p0.u].push_back(p0); swap(p0.u,p0.v); e1[p0.u].push_back(p0); } scanf("%d%d",&S,&T); // SPFA(S,dist,e,num); //SPFA(T,dist1,e1,num1); D(S,dist,e,num); D(T,dist1,e1,num1); /* for(i=1;i<=n;i++) printf("%d ",dist[i]); printf("\n"); for(i=1;i<=n;i++) printf("%d ",dist1[i]); printf("\n"); for(i=1;i<=n;i++) printf("%d %d\n",num[i],num1[i]);*/ sum=num[T]; for(i=1;i<=m;i++) if(dist[p[i].u]+dist1[p[i].v]+p[i].w==dist[T]+1&&dist[p[i].v]+dist1[p[i].v]==dist[T]) { sum+=num[p[i].u]*num1[p[i].v]; // printf("%d %d %d..\n",p[i].u,p[i].v,p[i].w); } printf("%d\n",sum); } return 0; }
用Dijkstra求时,将点一分为二,一个点分成最短的与次短的两个状态,然后每次找最小的状态,不断更新。
#include<stdio.h> #include<iostream> #include<vector> #include<algorithm> #include<string.h> using namespace std; const int maxn=1100; const int maxm=11000; const int maxint=0x3fffffff; struct point { int u,v,w; }p0,p[maxm]; vector<point> e[maxn]; int n,S,T,dist[maxn],dist1[maxn],num[maxn],num1[maxn]; void Dijkstra() { int i,j,k,ii; bool v1[maxn],v2[maxn],tag; for(i=1;i<=n;i++) v1[i]=false,v2[i]=false,dist[i]=maxint,dist1[i]=maxint,num[i]=0,num1[i]=0; dist[S]=0; num[S]=1; for(i=1;i<=2*n;i++) { for(k=maxint,ii=-1,j=1;j<=n;j++) { if(!v1[j]&&dist[j]<k) { tag=false; ii=j; k=dist[j]; } if(!v2[j]&&dist1[j]<k) { tag=true; ii=j; k=dist1[j]; } } if(ii==-1) break; if(!tag)//最小的状态为最短路 { v1[ii]=true; for(j=0;j<e[ii].size();j++) { if(dist[e[ii][j].v]>dist[ii]+e[ii][j].w) { dist1[e[ii][j].v]=dist[e[ii][j].v]; num1[e[ii][j].v]=num[e[ii][j].v]; dist[e[ii][j].v]=dist[ii]+e[ii][j].w; num[e[ii][j].v]=num[ii]; } else if(dist[e[ii][j].v]==dist[ii]+e[ii][j].w) num[e[ii][j].v]+=num[ii]; else if(dist1[e[ii][j].v]>dist[ii]+e[ii][j].w) { dist1[e[ii][j].v]=dist[ii]+e[ii][j].w; num1[e[ii][j].v]=num[ii]; } else if(dist1[e[ii][j].v]==dist[ii]+e[ii][j].w) num1[e[ii][j].v]+=num[ii]; } } else//最小的状态为次短路 { v2[ii]=true; for(j=0;j<e[ii].size();j++) { if(dist1[e[ii][j].v]>dist1[ii]+e[ii][j].w) { dist1[e[ii][j].v]=dist1[ii]+e[ii][j].w; num1[e[ii][j].v]=num1[ii]; } else if(dist1[e[ii][j].v]==dist1[ii]+e[ii][j].w) num1[e[ii][j].v]+=num1[ii]; } } } if(dist[T]+1==dist1[T]) printf("%d\n",num1[T]+num[T]); else printf("%d\n",num[T]); } int main() { int t,m,i; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); for(i=1;i<=n;i++) e[i].clear(); for(i=1;i<=m;i++) { scanf("%d%d%d",&p0.u,&p0.v,&p0.w); e[p0.u].push_back(p0); } scanf("%d%d",&S,&T); Dijkstra(); } return 0; }