题意:节点i能够通向若干节点,但其中只有一个节点是直接连通的,其余的需要搬道岔。给定起点和终点,为最少的搬道岔次数是多少?如果不能到达输出-1
思路:构图时,直接连通的权值设为0,需要搬道岔的权值设置为1,用dijkstra即可。
dijkstra可以用堆来实现,复杂度O(ElogV)。
#include <stdio.h> #include <string.h> #define N 102 #define INF N struct edge{ int y,w,next; }e[N*N]; int a,b,n; int first[N],dis[N],visited[N],top; void init(){ int i; top = 0; memset(visited,0,sizeof(visited)); memset(first,-1,sizeof(first)); for(i = 0;i<=n;i++) dis[i] = INF; } void add(int x,int y,int w){ e[top].y = y; e[top].w = w; e[top].next = first[x]; first[x] = top++; } int dijkstra(){ int i,min,pos; visited[a] = 1; for(i = first[a];i!=-1;i=e[i].next) dis[e[i].y] = e[i].w; while(1){ min = INF; for(i = 1;i<=n;i++) if(!visited[i] && dis[i]<min){ min = dis[i]; pos = i; } if(min == INF)//不再能找到最小值 return -1; visited[pos] = 1; if(pos == b) return dis[b]; for(i = first[pos];i!=-1;i=e[i].next) if(!visited[e[i].y] && dis[pos]+e[i].w<dis[e[i].y]) dis[e[i].y] = dis[pos]+e[i].w; } } int main(){ freopen("a.txt","r",stdin); while(scanf("%d %d %d",&n,&a,&b)!=EOF){ int i,j,k,num; init(); for(i = 1;i<=n;i++){ scanf("%d",&num); for(j = 0;j<num;j++){ scanf("%d",&k); if(!j)//直接相连 add(i,k,0); else//需要搬道岔 add(i,k,1); } } printf("%d\n",dijkstra()); } return 0; }
堆版本:
#include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <cstdlib> using namespace std; #define INF 0x3fffffff #define N 105 struct edge{ int y,next,w; bool operator<(const struct edge &b)const{ return w>b.w; } }e[N*N*2]; int first[N],top,n,a,b,used[N],dis[N]; priority_queue<struct edge> h; void add(int x,int y,int w){ e[top].w = w; e[top].y = y; e[top].next = first[x]; first[x] = top++; } int dijkstra(){ int i,j; memset(used, 0, sizeof(used)); for(i = 1;i<=n;i++) dis[i] = INF; dis[a] = 0; used[a] = 1; for(i = first[a];i!=-1;i=e[i].next){ h.push(e[i]); dis[e[i].y] = e[i].w; } while(!h.empty()){ struct edge now = h.top(),tmp; h.pop(); if(used[now.y]) continue; used[now.y] = 1; if(now.y == b) break; for(j = first[now.y];j!=-1;j=e[j].next){ if(!used[e[j].y] && dis[e[j].y]>dis[now.y]+e[j].w){ tmp.y = e[j].y; tmp.w = dis[now.y] + e[j].w; dis[e[j].y] = dis[now.y]+e[j].w; h.push(tmp);//一定注意此处:插入堆中的是更新后的从源点到e[j].y的最短路径长度 } } } if(dis[b] == INF) return -1; return dis[b]; } int main(){ int i,j,num; memset(first,-1,sizeof(first)); top = 0; scanf("%d %d %d",&n,&a,&b); for(i = 1;i<=n;i++){ scanf("%d",&num); if(num){ scanf("%d",&j); add(i,j,0); num--; } while(num--){ scanf("%d",&j); add(i,j,1); } } printf("%d\n",dijkstra()); return 0; }