Here We Go(relians) Again(HDU 2722)---建图繁琐

题目链接

题目描述

The Gorelians are a warlike race that travel the universe conquering new worlds as a form of recreation. Given their violent, fun-loving nature, keeping their leaders alive is of serious concern. Part of the Gorelian security plan involves changing the traffic patterns of their cities on a daily basis, and routing all Gorelian Government Officials to the Government Building by the fastest possible route.
Fortunately for the Gorelian Minister of Traffic (that would be you), all Gorelian cities are laid out as a rectangular grid of blocks, where each block is a square measuring 2520 rels per side (a rel is the Gorelian Official Unit of Distance). The speed limit between two adjacent intersections is always constant, and may range from 1 to 9 rels per blip (a blip, of course, being the Gorelian Official Unit of Time). Since Gorelians have outlawed decimal numbers as unholy (hey, if you’re the dominant force in the known universe, you can outlaw whatever you want), speed limits are always integer values. This explains why Gorelian blocks are precisely 2520 rels in length: 2520 is the least common multiple of the integers 1 through 9. Thus, the time required to travel between two adjacent intersections is always an integer number of blips.
In all Gorelian cities, Government Housing is always at the northwest corner of the city, while the Government Building is always at the southeast corner. Streets between intersections might be one-way or two-way, or possibly even closed for repair (all this tinkering with traffic patterns causes a lot of accidents). Your job, given the details of speed limits, street directions, and street closures for a Gorelian city, is to determine the fastest route from Government Housing to the Government Building. (It is possible, due to street directions and closures, that no route exists, in which case a Gorelian Official Temporary Holiday is declared, and the Gorelian Officials take the day off.)
在这里插入图片描述
The picture above shows a Gorelian City marked with speed limits, one way streets, and one closed street. It is assumed that streets are always traveled at the exact posted speed limit, and that turning a corner takes zero time. Under these conditions, you should be able to determine that the fastest route from Government Housing to the Government Building in this city is 1715 blips. And if the next day, the only change is that the closed road is opened to two way traffic at 9 rels per blip, the fastest route becomes 1295 blips. On the other hand, suppose the three one-way streets are switched from southbound to northbound (with the closed road remaining closed). In that case, no route would be possible and the day would be declared a holiday.

输入格式

The input consists of a set of cities for which you must find a fastest route if one exists. The first line of an input case contains two integers, which are the vertical and horizontal number of city blocks, respectively. The smallest city is a single block, or 1 by 1, and the largest city is 20 by 20 blocks. The remainder of the input specifies speed limits and traffic directions for streets between intersections, one row of street segments at a time. The first line of the input (after the dimensions line) contains the data for the northernmost east-west street segments. The next line contains the data for the northernmost row of north-south street segments. Then the next row of east-west streets, then north-south streets, and so on, until the southernmost row of east-west streets. Speed limits and directions of travel are specified in order from west to east, and each consists of an integer from 0 to 9 indicating speed limit, and a symbol indicating which direction traffic may flow. A zero speed limit means the road is closed. All digits and symbols are delimited by a single space. For east-west streets, the symbol will be an asterisk ‘*’ which indicates travel is allowed in both directions, a less-than symbol ‘<’ which indicates travel is allowed only in an east-to-west direction, or a greater-than symbol ‘>’ which indicates travel is allowed only in a west-to-east direction. For north-south streets, an asterisk again indicates travel is allowed in either direction, a lowercase “vee” character ‘v’ indicates travel is allowed only in a north-to-south directions, and a caret symbol ‘^’ indicates travel is allowed only in a south-to-north direction. A zero speed, indicating a closed road, is always followed by an asterisk. Input cities continue in this manner until a value of zero is specified for both the vertical and horizontal dimensions.

输出格式

For each input scenario, output a line specifying the integer number of blips of the shortest route, a space, and then the word “blips”. For scenarios which have no route, output a line with the word “Holiday”.

输入样例

2 2
9 * 9 *
6 v 0 * 8 v
3 * 7 *
3 * 6 v 3 *
4 * 8 *
2 2
9 * 9 *
6 v 9 * 8 v
3 * 7 *
3 * 6 v 3 *
4 * 8 *
2 2
9 * 9 *
6 ^ 0 * 8 ^
3 * 7 *
3 * 6 ^ 3 *
4 * 8 *
0 0

输出样例

1715 blips
1295 blips
Holiday

分析

建图比较麻烦,主要是定位好点之后按照奇偶数建立水平边和垂直边,建完图之后套用最短路模板就行了。
具体参考代码,以下分别是dijkstra、SPFA和SPFA(SLF优化)的源码。

源程序

Dijkstra算法

#include <bits/stdc++.h>
#define MAXN 505
using namespace std;
struct Edge{	//链式前向星
	int v,w,next;
	Edge(){};
	Edge(int _v,int _w,int _next){
		v=_v,w=_w,next=_next;
	};
	bool operator <(const Edge a)const{	//重载<符号
		return w>a.w;
	};
}edge[2*MAXN];
char str[MAXN];
int EdgeCount,head[MAXN];
int n,row,col,dis[MAXN];
bool used[MAXN];
void addEdge(int u,int v,int w)	//链式前向星建图
{
	edge[++EdgeCount]=Edge(v,w,head[u]);
	head[u]=EdgeCount;
}
void dijkstra()
{
	priority_queue<Edge> q;	//优先队列---小顶堆
	memset(dis,0x3f,sizeof(dis));
	memset(used,false,sizeof(used));
	dis[1]=0;
	q.push(Edge{1,0,0});
	while(!q.empty()){
		int u=q.top().v;q.pop();
		if(used[u])continue;	//如果已经确定了最短路径就直接进入下次循环
		used[u]=true;	
		for(int i=head[u];i;i=edge[i].next){
			int v=edge[i].v,w=edge[i].w;
			if(dis[v]>dis[u]+w){	//更新最短路
				dis[v]=dis[u]+w;
				q.push(Edge{v,dis[v],0});
			}
		}
	}
	if(dis[n]==0x3f3f3f3f)printf("Holiday\n");
	else printf("%d blips\n",dis[n]);
}
int main()
{
	while(scanf("%d%d",&row,&col)&&(row||col)){	//row代表垂直边数,col代表水平边数
		getchar();	//吞掉换行符
		memset(head,0,sizeof(head));	//初始化
		EdgeCount=0;
		n=(row+1)*(col+1);	//总顶点数
		for(int i=1;i<=2*row+1;i++){	//建图 
			gets(str);
			if(i&1){	//行信息 
				for(int j=1;j<=col;j++){
					int u=(i-1)/2*(col+1)+j;	//左顶点 
					int speed=str[(j-1)*4]-'0'; 	//速度 
					char c=str[(j-1)*4+2];		//符号 
					if(speed>0){
						if(c=='*'){		//无向边 
							addEdge(u,u+1,2520/speed);
							addEdge(u+1,u,2520/speed);
						}
						else if(c=='>') //从左到右	 
							addEdge(u,u+1,2520/speed);
						else	//从右到左 
							addEdge(u+1,u,2520/speed);
					}
				}
			}
			else{	//列信息 
				for(int j=1;j<=col+1;j++){
					int u=(i-1)/2*(col+1)+j;	//上顶点 
					int speed=str[(j-1)*4]-'0'; 	//速度 
					char c=str[(j-1)*4+2];		//符号 
					if(speed>0){
						if(c=='*'){		//无向边 
							addEdge(u,u+col+1,2520/speed);
							addEdge(u+col+1,u,2520/speed);
						}
						else if(c=='v') //从上到下	 
							addEdge(u,u+col+1,2520/speed);
						else	//从下到上 
							addEdge(u+col+1,u,2520/speed);
					}
				}
			}
		}
		dijkstra();
	}	
} 

SPFA算法

#include <bits/stdc++.h>
#define MAXN 505
using namespace std;
struct Edge{	//链式前向星 
	int v,w,next;
	Edge(){};
	Edge(int _v,int _w,int _next){
		v=_v,w=_w,next=_next;
	};
}edge[2*MAXN];
char str[MAXN];
int EdgeCount,head[MAXN];
int n,row,col,dis[MAXN],ven[MAXN],nums[MAXN];
void addEdge(int u,int v,int w)	//链式前向星建图 
{
	edge[++EdgeCount]=Edge(v,w,head[u]);
	head[u]=EdgeCount;
}
void SPFA()
{
	queue<int> q;	
	memset(dis,0x3f,sizeof(dis));
	memset(ven,0,sizeof(ven));
	memset(nums,0,sizeof(nums));
	dis[1]=0;
	ven[1]=nums[1]=1;
	q.push(1);
	while(!q.empty()){
		int u=q.front();q.pop();
		ven[u]=0;
		for(int i=head[u];i;i=edge[i].next){
			int v=edge[i].v,w=edge[i].w;
			if(dis[v]>dis[u]+w){	//找到新的最小值 
				dis[v]=dis[u]+w;
				if(!ven[v]){	//v不在队列中 
					q.push(v);
					ven[v]=1;	//标记在队列中 
//					nums[v]++;	判断负环 
//					if(nums[v]>n){
//						printf("Holiday\n");
//						return ;
//					}
				} 
			}
		}
	}
	if(dis[n]==0x3f3f3f3f)printf("Holiday\n");
	else printf("%d blips\n",dis[n]);
	return ;
}
int main()
{
	while(scanf("%d%d",&row,&col)&&(row||col)){	//row代表垂直边数,col代表水平边数
		getchar();	//吞掉换行符 
		memset(head,0,sizeof(head));
		EdgeCount=0;
		n=(row+1)*(col+1);	//总顶点数
		for(int i=1;i<=2*row+1;i++){	//建图 
			gets(str);
			if(i&1){	//行信息 
				for(int j=1;j<=col;j++){
					int u=(i-1)/2*(col+1)+j;	//左顶点 
					int speed=str[(j-1)*4]-'0'; 	//速度 
					char c=str[(j-1)*4+2];		//符号 
					if(speed>0){
						if(c=='*'){		//无向边 
							addEdge(u,u+1,2520/speed);
							addEdge(u+1,u,2520/speed);
						}
						else if(c=='>') //从左到右	 
							addEdge(u,u+1,2520/speed);
						else	//从右到左 
							addEdge(u+1,u,2520/speed);
					}
				}
			}
			else{	//列信息 
				for(int j=1;j<=col+1;j++){
					int u=(i-1)/2*(col+1)+j;	//上顶点 
					int speed=str[(j-1)*4]-'0'; 	//速度 
					char c=str[(j-1)*4+2];		//符号 
					if(speed>0){
						if(c=='*'){		//无向边 
							addEdge(u,u+col+1,2520/speed);
							addEdge(u+col+1,u,2520/speed);
						}
						else if(c=='v') //从上到下	 
							addEdge(u,u+col+1,2520/speed);
						else	//从下到上 
							addEdge(u+col+1,u,2520/speed);
					}
				}
			}
		}
		SPFA();
	}	
} 

SPFA算法之SLF优化

#include <bits/stdc++.h>
#define MAXN 505
using namespace std;
struct Edge{	//链式前向星 
	int v,w,next;
	Edge(){};
	Edge(int _v,int _w,int _next){
		v=_v,w=_w,next=_next;
	};
}edge[2*MAXN];
char str[MAXN];
int EdgeCount,head[MAXN];
int n,row,col,dis[MAXN],ven[MAXN],nums[MAXN];
void addEdge(int u,int v,int w)	//链式前向星建图 
{
	edge[++EdgeCount]=Edge(v,w,head[u]);
	head[u]=EdgeCount;
}
void SPFA()
{
	deque<int> q;
	memset(dis,0x3f,sizeof(dis));
	memset(ven,0,sizeof(ven));
	memset(nums,0,sizeof(nums));
	dis[1]=0;
	ven[1]=nums[1]=0;
	q.push_back(1);
	int cnt;
	while(cnt=q.size()){
		int u=q.front();q.pop_front();
		ven[u]=0;
		for(int i=head[u];i;i=edge[i].next){
			int v=edge[i].v,w=edge[i].w;
			if(dis[v]>dis[u]+w){	//找到新的最小值 
				dis[v]=dis[u]+w;
				if(!ven[v]){	//v不在队列中 
					if(cnt>1&&dis[v]>dis[q.front()])q.push_front(v); //如果dis[v]比队首元素值还小,优先更新 
					else q.push_back(v);
					ven[v]=1;	//标记在队列中 
//					nums[v]++;	判断负环 
//					if(nums[v]>n){
//						printf("Holiday\n");
//						return ;
//					}
				} 
			}
		}
	}
	if(dis[n]==0x3f3f3f3f)printf("Holiday\n");
	else printf("%d blips\n",dis[n]);
	return ;
}
int main()
{
	while(scanf("%d%d",&row,&col)&&(row||col)){	//row代表垂直边数,col代表水平边数
		getchar();	//吞掉换行符
		memset(head,0,sizeof(head));
		EdgeCount=0;
		n=(row+1)*(col+1);	//总顶点数
		for(int i=1;i<=2*row+1;i++){	//建图 
			gets(str);
			if(i&1){	//行信息 
				for(int j=1;j<=col;j++){
					int u=(i-1)/2*(col+1)+j;	//左顶点 
					int speed=str[(j-1)*4]-'0'; 	//速度 
					char c=str[(j-1)*4+2];		//符号 
					if(speed>0){
						if(c=='*'){		//无向边 
							addEdge(u,u+1,2520/speed);
							addEdge(u+1,u,2520/speed);
						}
						else if(c=='>') //从左到右	 
							addEdge(u,u+1,2520/speed);
						else	//从右到左 
							addEdge(u+1,u,2520/speed);
					}
				}
			}
			else{	//列信息 
				for(int j=1;j<=col+1;j++){
					int u=(i-1)/2*(col+1)+j;	//上顶点 
					int speed=str[(j-1)*4]-'0'; 	//速度 
					char c=str[(j-1)*4+2];		//符号 
					if(speed>0){
						if(c=='*'){		//无向边 
							addEdge(u,u+col+1,2520/speed);
							addEdge(u+col+1,u,2520/speed);
						}
						else if(c=='v') //从上到下	 
							addEdge(u,u+col+1,2520/speed);
						else	//从下到上 
							addEdge(u+col+1,u,2520/speed);
					}
				}
			}
		}
		SPFA();
	}	
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值