您的位置:首页 > 其它

hdu2482 transit search

2015-09-12 20:58 288 查看
第一次做大牛们口中的“阅读题”,顿时感觉智商被碾压...

虽然读懂题意后就是很简单的最短路,但网上大牛们不带注释的题解对于博主这种弱渣简直同天书一般orz

于是AC后将此(水)题整理一下,加些注释,以方便查阅,大牛们飘过就好orz

题目大意:给出起点、终点、车站的位置和一些公交线路,分三种情况输出:(1)起点离终点够近,走过去;(2)起点离终点太远,但起点和终点附近都有车站,求最小乘车数(一站到底就是1,每换乘1趟+1);(3)起点离终点太远,且附近无车站,或者不可达,就打出租车;

将乘车数看做距离就是最短路问题了,大概有三种建图方法:http://blog.csdn.net/qq564690377/article/details/8053877,这里博主采用的是最后一种

拿第二组输入为例,建好图后大概像这样:



很容易就看出从起点到终点要上下车共4次,也就是搭两趟车

这方法挺神奇的...不用考虑重复建点(两线路都过b点的话建两个点)

这题貌似有个神奇的结论:从起点走到车站,不搭公车,直接走到终点,应该会输出一个0(博主没试过)。当然就结果而言这是对的,不过有些微妙。

#include<bits/stdc++.h>
#define maxv 5010
using namespace std;
const int len[8]={5120,2560,1280,640,320,160,80,40};
struct Point{
	int x,y;//点的位置(x,y)
	
	inline void read(){cin>>x>>y;}//读入点的位置
	inline void readFromS(){//单独处理start和end
		string s;
		int rx,ry;
		cin>>s>>rx>>ry;
		int dx=0,dy=0;
		for(int i=0;i<8;i++){
			if(s[i]=='1'||s[i]=='3') dy+=len[i];
			if(s[i]=='2'||s[i]=='3') dx+=len[i];
		}
		x=dx+(rx<<2);y=dy+(ry<<2);
	}
	double Length(Point b){return sqrt((double)(x-b.x)*(x-b.x)+(double)(y-b.y)*(y-b.y));}//求距离
}ps[maxv],&star=ps[0],&fin=ps[1];//实点集,0为start,1为end

struct Edge{
	int to,cost;
	Edge(int to,int cost):to(to),cost(cost){}
};
vector<Edge> G[maxv+200];//邻接表

int inf,d[maxv];//d[]记录上下车次数(距离)

typedef pair<int,int> P;<dist,node>
void Dijkstra(){//最短路,没什么要讲的吧?
	priority_queue<P,vector<P>,greater<P> > p;
	memset(d,0x0f,sizeof d);
	inf=d[1],d[0]=0;
	p.push(P(0,0));
	
	while(!p.empty()&&d[1]==inf){
		int v=p.top().second,cost=p.top().first;p.pop();
		if(d[v]<cost) continue;
		int size=G[v].size();
		for(int i=0;i<size;i++){
			Edge e=G[v][i];
			if(d[e.to]>d[v]+e.cost){
				d[e.to]=d[v]+e.cost;
				p.push(P(d[e.to],e.to));
			}
		}
	}
}

bool hasline,tooshort;
const string walk("walk there"),taxi("take a taxi");
void SOLVE()
{
	if(tooshort) {cout<<walk<<endl;return;}//太短
	else if(!hasline) {cout<<taxi<<endl;return;}//start或end的其中之一离车站过远
	
	Dijkstra();
	if(d[1]==inf) cout<<taxi<<endl;
	else cout<<(d[1]>>1)<<endl;//乘车次数=上下车次数和/2
}

void INPUT()
{
	int N,M;
	
	//start和end建点
	star.readFromS();fin.readFromS();
	tooshort=star.Length(fin)<=2000.0;//太短
	G[0].clear(),G[1].clear();
	
	
	//对每个车站分别建点
	map<string,int> m;//将车站名转为数字
	cin>>N;
	string s;
	int tot=2;
	while(N--){
		cin>>s;
		m[s]=tot;
		ps[tot++].read();
	}
	
	//给距离start或end一千米以内的车站连单向边(start->车站 或 车站->end)
	bool sto=false,tof=false;
	for(int i=2;i<tot;i++){
		G[i].clear();
		if(star.Length(ps[i])<=1000.0) G[0].push_back(Edge(i,0)),sto=true;//从start走到车站过程中不用上下车
		if(fin.Length(ps[i])<=1000.0) G[i].push_back(Edge(1,0)),tof=true;
	}
	hasline=sto&&tof;//start和end是否都能到达车站
	
	//给公交线路建点并将其连与对应车站连双向边(车站<->线路)
	cin>>M;
	int k;
	while(M--){
		cin>>k;
		G[tot].clear();
		while(k--){
			cin>>s;
			int no=m[s];
			G[tot].push_back(Edge(no,1));//下车
			G[no].push_back(Edge(tot,1));//上车
		}
		tot++;
	}
}

void MAIN()
{
	int T;
	cin>>T;
	while(T--) INPUT(),SOLVE();
}

int main()
{
	ios::sync_with_stdio(false);
	//freopen("in.txt","r",stdin);
	//freopen("out.txt","w",stdout);
	MAIN();
	return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: