PAT 1131. Subway Map (30) 地铁换乘,优先BFS搜图应用


/*************************
题意:
一个特殊的地铁图
求s到e的最短距离路线
如果距离相同,求换乘次数最少的路线
************************/
/***********************
解题思路:
由于点可能有10000个,用dijkstr容易超时
而这里的特点是只有100条地铁站,每个点最多5个度
即有很多情况是只有1个选择的情况(笔直向下走)
因此,我们选择使用BFS,能充分利用这个特性。

储存图是要把边也存进去,为了判断是否换乘,我们是利用边的组id去判断的。

入队的是行进状态State
	该状态包括当前站,当前线路组id,当前行进距离,和当前换乘距离
然后利用优先队列去做队列
因为结果不唯一,所以我们可以设置一个vis[],已经出队的点,就设置vis=1
接下来这个点不需要再入队。
处理要怎么计算换乘和储存换乘节点即可。
*************************/
/***********************
注意:
	优先bfs时,注意vis只在入队时判断,只在出队时去设1
*********************/
#include<iostream>
#include<stdio.h>
#include<string>
#include<vector>
#include<queue>
#include<stdlib.h>
#include<algorithm>
#include<string.h>
#include<stack>
#include<map>
#include<set>
#include<unordered_map>
using namespace std;
#define M 10005
#define INF 0x7ffffff

vector<int> edg[M];
struct Road{
	int s;
	int e;
	int id;
};
Road road[M];

struct State{
	int dis;
	int cnum; //change num
	int nowcity;
	int nowroad;
	vector<int> cv;
	vector<int> rv;
    bool operator < (const State & a) const{
		if(dis > a.dis)
			return true;
		else if(dis == a.dis)
			return cnum > a.cnum;
		else return false;
    }
};
int vis[M];
void dijk(int start,int end){
	int i;
	priority_queue<State> q;
	memset(vis,0,sizeof(vis));
	State sta;
	sta.cnum = 0;
	sta.nowcity = start;
	sta.dis = 0;
	sta.nowroad = -1;
	q.push(sta);
	int city;
	Road r;
	int e;
	State pushs;
	while(!q.empty()){
		sta = q.top();
		q.pop();
		city = sta.nowcity;
		vis[city] = 1;
		if(city == end){
			int lastc;
			sta.cv.push_back(end);
			cout<<sta.dis<<endl;
			for(i = 0;i < sta.rv.size();i++){
				printf("Take Line#%d from %04d to %04d.\n",sta.rv[i],sta.cv[i],sta.cv[i+1]);
			}
			break;
		}
		for(i = 0;i < edg[city].size();i++){
			pushs = sta;
			r = road[edg[city][i]];
			if(r.s == city)
				e = r.e;
			else e = r.s;

			if(vis[e])
				continue;
			if(r.id != sta.nowroad){
				pushs.cnum++;
				pushs.cv.push_back(sta.nowcity); //将变换处的起点放入
				pushs.rv.push_back(r.id);
				pushs.nowroad = r.id;
			}
			pushs.dis++;
			pushs.nowcity = e;
			q.push(pushs);
		}
	}
}



int main(){
	int n, i, m, k;
	int j,node,lastnode;
	scanf("%d",&n);

	j=0;
	for(i = 1;i <= n;i++){
		scanf("%d",&k);
		lastnode = -1;
		while(k--){
			scanf("%d",&node);
			if(lastnode != -1){
				edg[lastnode].push_back(j);
				edg[node].push_back(j);
				road[j].s = lastnode;
				road[j].e = node;
				road[j].id = i;
				j++;
			}
			lastnode = node;
		}
	}	
	cin>>k;
	int s, e;
	while(k--){
		cin>>s>>e;
		dijk(s,e);
	}

	return 0;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值