题目:http://acm.scs.bupt.cn/onlinejudge/showproblem.php?problem_id=1095
题意:这题要在一个无向正权图上找单源最短路,找到目标点后,还要求出到达这个点的最短路径的数量。有重边。
解法:dijkstra+DP。正权图找最短路首先想到dijkstra,然后考虑如何获得最短路数量和怎样处理重边。因为两点间只需一条最的路径就够了,因此记录图的时候可以考虑忽略其他权比较高的路径,只记录最短的那条。并且增加一个二元数组记录相邻点间的最短路径条数。此外有数组d记录起点到各点的最短距离,count记录到达这点的最短路径数。在dijkstra过程中,加入新节点后松弛没找到最短路的点的过程中,考虑如果松弛过程中d[i]==d[pos]+map[pos][i],则count[i]+=count[pos]*p[pos][i](此处之前错误写成了count[i]++,-_-!),如果d[i]>d[pos]+map[pos][i],则count[i]=count[pos]*p[pos][i]。最后输出d[b],count[b]就行,注意各数组初始化,并且注意是两组输出之间有空行,最后一组输出后不用空行,仅换行,这里我也悲剧了一次。
code:
#include<stdio.h> #include<stdlib.h> #include<memory.h> int main() { long cur,pos,temp; long f,m,n,i,j,x,y,l,a,b; long map[310][310],p[310][310],count[310],d[310],flag[310]; scanf("%ld",&f); while(f--) { scanf("%ld%ld",&n,&m); memset(map,0,sizeof(long)*310*310); for(i=0;i<m;i++) { scanf("%ld%ld%ld",&x,&y,&l); if(map[x][y]&&map[x][y]==l) { p[x][y]++; p[y][x]++; } else if(map[x][y]&&map[x][y]>l) { map[x][y]=l; map[y][x]=l; p[x][y]=1; p[y][x]=1; } else if(!map[x][y]) { map[x][y]=l; map[y][x]=l; p[x][y]=1; p[y][x]=1; } } scanf("%ld%ld",&a,&b); for(i=0;i<=n;i++) { flag[i]=0; d[i]=1000000000; } d[a]=0; flag[a]=1; cur=a; count[a]=1; for(i=1;i<=n;i++) { if(map[a][i]) { d[i]=map[a][i]; count[i]=count[a]*p[a][i]; } } while(!flag[b]) { temp=1000000000; pos=-1; for(i=1;i<=n;i++) { if(!flag[i]&&d[i]&&d[i]<temp) { temp=d[i]; pos=i; } } if(pos==-1) break; flag[pos]=1; for(i=1;i<=n;i++) { if(!flag[i]&&i!=pos&&map[pos][i]&&d[i]==d[pos]+map[pos][i]) { count[i]+=count[pos]*p[pos][i]; } else if(!flag[i]&&i!=pos&&map[pos][i]&&d[i]>d[pos]+map[pos][i]) { d[i]=d[pos]+map[pos][i]; count[i]=count[pos]*p[pos][i]; } } } if(flag[b]) { printf("%ld %ldn",d[b],count[b]); } else { printf("Poor Javamann"); } if(f!=0) printf("n"); } }
Leave a Reply