题意:节点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;
}