题目链接: http://poj.org/problem?id=1847
题目大意: 这道题理解起来有点恶心
有N个铁轨交叉口,这些交叉口与其他交叉口通过铁轨连接
电车开进一个交叉口,想去另一个交叉口,必须要把灯照向下一个交叉口
求从A到B驾驶员需要转换灯的最小次数
解题思路: 这道题关键在于构图,每一个交叉点连接的第一条边为0
其他的边为1,求A到B的最短路径
感想: 本来想找一道Dijkstra的题,试验最小二叉堆优化之后的效率
理解了题目发现顶点最大才100,堆的效率很难体现出来
而且这道题用SPFA更加方便,开始WA了几次
原来是入队时判断错了,写过这么多的SPFA,真不应该
SPFA的思想:每走一个点,修改到这个点的当前最优解,下次再准备走这点
时判断这次的解是不是比上一次还优?是则入队,即使到达终点也不用停止,最
优解总会有界限,所以当队列为空的时候,就是最优解!
代码:
//SPFA最短路模版 //入队的时候需要注意不要判断错了! #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX 101 #define INF 0x3f3f3f3f int n,m,visit[MAX],list[MAX*MAX],near[MAX],edge[MAX][MAX]; int SPFA(int A,int B) { int e,s,i,v0; e=s=0; list[s++]=A; //初始化 visit[A]=1; near[A]=0; while(s!=e) { v0=list[e++]; visit[v0]=0; for(i=1;i<=n;i++) { if(edge[v0][i]<INF&&near[v0]+edge[v0][i]<near[i]) { if(!visit[i]) //**这里最容易错误了** { list[s++]=i; visit[i]=1; } near[i]=near[v0]+edge[v0][i]; //即使队列里面有,也要改变它的值 } } } return near[B]; } int main() { int i,j,k,A,B,to; while(scanf("%d%d%d",&n,&A,&B)!=EOF) { memset(edge,INF,sizeof(edge)); memset(near,INF,sizeof(near)); memset(visit,0,sizeof(visit)); for(i=1;i<=n;i++) //构图过程 { scanf("%d",&m); for(j=1;j<=m;j++) { scanf("%d",&to); if(j==1) edge[i][to]=0; //第一条边为0 else edge[i][to]=1; //其余的边为1 } } if(A==B) //终点和起点一样,直接输出 { printf("0\n"); return 0; } k=SPFA(A,B); if(k==INF) //不可到达B点 printf("-1\n"); else printf("%d\n",k); } return 0; }注:原创文章,转载求注明出处