HDU2112 HDU Today(哈希+dijkstra/暴力+floyd)[C,C++]

题目及翻译

题面

经过锦囊相助,海东集团终于度过了危机,从此,HDU的发展就一直顺风顺水,到了2050年,集团已经相当规模了,据说进入了钱江肉丝经济开发区500强。这时候,XHD夫妇也退居了二线,并在风景秀美的诸暨市浬浦镇陶姚村买了个房子,开始安度晚年了。
这样住了一段时间,徐总对当地的交通还是不太了解。有时很郁闷,想去一个地方又不知道应该乘什么公交车,在什么地方转车,在什么地方下车(其实徐总自己有车,却一定要与民同乐,这就是徐总的性格)。
徐总经常会问蹩脚的英文问路:“Can you help me?”。看着他那迷茫而又无助的眼神,热心的你能帮帮他吗?
请帮助他用最短的时间到达目的地(假设每一路公交车都只在起点站和终点站停,而且随时都会开)。

输入

输入数据有多组,每组的第一行是公交车的总数N(0<=N<=10000);
第二行有徐总的所在地start,他的目的地end;
接着有n行,每行有站名s,站名e,以及从s到e的时间整数t(0<t<100)(每个地名是一个长度不超过30的字符串)。
note:一组数据中地名数不会超过150个。
如果N==-1,表示输入结束。

输出

如果徐总能到达目的地,输出最短的时间;否则,输出“-1”。

输入样例

6
xiasha westlake
xiasha station 60
xiasha ShoppingCenterofHangZhou 30
station westlake 20
ShoppingCenterofHangZhou supermarket 10
xiasha supermarket 50
supermarket westlake 10
-1

输出样例

50

提示

最佳路径为xiasha->ShoppingCenterofHangZhou->supermarket->westlake

题目思路

题目分为两个部分,哈希和最短路
也就是先把字符串转化为下标,然后再当成最短路模板题做
最短路就是纯模板,目前我常用的两点最短路算法应该是dijkstra
(题目给了15秒,所以floyd估计也行)
哈希部分也是纯模板,注意实际上要哈希两次,第一次把字符串映射为数字,第二次把数组映射为下标
(但是我试了暴力直接算下标也行)
提供两种代码
一种是哈希模板+dijkstra模板 这个比较快
一种是暴力找下标+floyd模板 这个比较慢但是好理解也好写
读者也可自行搭配,哈希+floyd或者暴力+dijkstra也能过

注意事项

模板题该有的坑都有
起点和终点相同、重边、起点无法到达终点、边数为0等
c++可以用map或者unordered_map代替哈希来映射,但是速度不咋地

AC代码

哈希模板 + dijkstra模板(较快)

C/C++(几乎没有代码变更)

用时514MS 内存1916K 长度2420B

#include<stdio.h>
#include<string.h>//memset函数所在
const int INF = 0x3f3f3f3f;//最大值,这个值方便初始化
const int P = 151;//大于 最地点数(150)的 最小素数 是151
int n,a,b,c,cnt,op,ed;//cnt用于记录点的个数,op和ed分别是起点终点
int id[200];//用于第二次映射 把哈希值映射为下标
char s[35];
char place[200][35];//用于第一次映射 把字符串映射为哈希值
int grid[200][200];//邻接表
int dis[200],vis[200];
void init(){
	memset(id,-1,sizeof(id));//初始化id为-1,因为cnt起始为0
	memset(place,0,sizeof(place));
	cnt = 0;
	memset(grid,0x3f,sizeof(grid));//初始化后邻接表中的值 == INF
	memset(vis,0,sizeof(vis));
}
int HS(){
	int len = strlen(s);
	int val = 0;
	for(int i=0;i<len;++i)val += s[i];//随便把字符串转化成数字一下
	int tmp = val;
	for(int i=0;i<P;++i){
		tmp %= P;//把数字范围限制到P之内
		if(strlen(place[tmp]) == 0)break;//如果这个位置没有放入元素,就弹出
		if(strcmp(s,place[tmp]) == 0)return id[tmp];//如果位置的元素和输入的相同,输出其对应下标
		++tmp;//如果位置被其他元素占了,就往前探测
	}
	strcpy(place[tmp],s);//把输入的元素放入这个位置
	if(id[tmp] == -1)id[tmp] = cnt++;//如果这个位置没有记录过,就记录一下
	return id[tmp];//输出其对应下标
}
int getNewPlace(){//方便写代码
	scanf("%s",s);
	return HS();
}
void dijkstra(){//模板
	for(int i=0;i<cnt;++i){//获得起点到每个点的位置
		dis[i] = grid[op][i];
	}
	vis[op] = 1;//起点已经被走过
	dis[op] = 0;//起点到自己长度为0,这是个坑点
	for(int i=0;i<cnt;++i){//最多遍历所有点
		int temp = INF;
		int flag = -1;
		for(int j=0;j<cnt;++j){//得到目前离起点最近的没走过的点
			if(vis[j])continue;
			if(temp > dis[j]){
				temp = dis[j];
				flag = j;
			}
		}
		if(flag == -1)break;//如果没有更多点了直接退出
		vis[flag] = 1;//这个点是中转点,本身不用被计算
		for(int j=0;j<cnt;++j){
			if(vis[j])continue;
			if(dis[j] > dis[flag] + grid[flag][j]){//比较直接到J 和 经过flag再到J 的距离
				dis[j] = dis[flag] + grid[flag][j];//更新最小距离
			}
		}
	}
}
int main(){
	while(scanf("%d",&n),n != -1){//-1 退出
		init();//清空数组
		op = getNewPlace();//输入起点
		ed = getNewPlace();//输入终点
		for(int i=0;i<n;++i){
			a = getNewPlace();//输入点a
			b = getNewPlace();//输入点b
			scanf("%d",&c);
			if(c < grid[a][b]){//判断重边
				grid[a][b] = c;
				grid[b][a] = c;
			}
		}
		dijkstra();
		if(dis[ed] == INF)printf("-1\n");//判断是否能走到
		else printf("%d\n",dis[ed]);
	}
	return 0;
}

暴力找下标 + floyd模板

C/C++(几乎没有代码变更)

用时1232MS 内存1868K 长度1518 B

#include<stdio.h>
#include<string.h>//memset函数所在
const int INF = 0x3f3f3f3f;//最大值,这个值方便初始化
const int P = 151;//大于 最地点数(150)的 最小素数 是151
int n,a,b,c,cnt,op,ed;//cnt用于记录点的个数,op和ed分别是起点终点
char s[35];
char place[200][35];//用于第一次映射 把字符串映射为哈希值
int grid[200][200];//邻接表
void init(){
	memset(place,0,sizeof(place));
	cnt = 0;
	memset(grid,0x3f,sizeof(grid));//初始化后邻接表中的值 == INF
}
int getNewPlace(){
	scanf("%s",s);
	int i;
	for(i=0;i<200;++i){
		if(strlen(place[i]) == 0)break;
		if(strcmp(place[i],s) == 0){
			if(cnt < i)cnt = i;
			return i;
		}
	}
	strcpy(place[i],s);
	if(cnt < i)cnt = i;
	return i;
}
void floyd(){
	grid[op][op] = 0;////起点到自己长度为0,这是个坑点
	for(int k=0;k<=cnt;++k){//遍历所有中转点
		for(int i=0;i<=cnt;++i){//遍历所有起点
			for(int j=0;j<=cnt;++j){//遍历所有终点
				if(grid[i][j] > grid[i][k] + grid[k][j]){//比较i到j 和 i经过k再到J 的距离
					grid[i][j] = grid[i][k] + grid[k][j];//更新最小距离
				}
			}
		}
	}
}
int main(){
	while(scanf("%d",&n),n != -1){//-1 退出
		init();//清空数组
		op = getNewPlace();//输入起点
		ed = getNewPlace();//输入终点
		for(int i=0;i<n;++i){
			a = getNewPlace();//输入点a
			b = getNewPlace();//输入点b
			scanf("%d",&c);
			if(c < grid[a][b]){//判断重边
				grid[a][b] = c;
				grid[b][a] = c;
			}
		}
		floyd();
		if(grid[op][ed] == INF)printf("-1\n");//判断能否走到
		else printf("%d\n",grid[op][ed]);
	}
	return 0;
}

本文作者 CSDN@扶她小藜
个人主页链接 https://blog.csdn.net/weixin_44579869

发布了15 篇原创文章 · 获赞 2 · 访问量 723

猜你喜欢

转载自blog.csdn.net/weixin_44579869/article/details/104530211