HDU 2066 一个人的旅行 <裸的迪杰斯特拉算法+虚拟顶点法>

来源:互联网 发布:药代动力学考研知乎 编辑:程序博客网 时间:2024/05/16 11:55

一个人的旅行

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 24776    Accepted Submission(s): 8592


Problem Description
虽然草儿是个路痴(就是在杭电待了一年多,居然还会在校园里迷路的人,汗~),但是草儿仍然很喜欢旅行,因为在旅途中 会遇见很多人(白马王子,^0^),很多事,还能丰富自己的阅历,还可以看美丽的风景……草儿想去很多地方,她想要去东京铁塔看夜景,去威尼斯看电影,去阳明山上看海芋,去纽约纯粹看雪景,去巴黎喝咖啡写信,去北京探望孟姜女……眼看寒假就快到了,这么一大段时间,可不能浪费啊,一定要给自己好好的放个假,可是也不能荒废了训练啊,所以草儿决定在要在最短的时间去一个自己想去的地方!因为草儿的家在一个小镇上,没有火车经过,所以她只能去邻近的城市坐火车(好可怜啊~)。
 

Input
输入数据有多组,每组的第一行是三个整数T,S和D,表示有T条路,和草儿家相邻的城市的有S个,草儿想去的地方有D个;
接着有T行,每行有三个整数a,b,time,表示a,b城市之间的车程是time小时;(1=<(a,b)<=1000;a,b 之间可能有多条路)
接着的第T+1行有S个数,表示和草儿家相连的城市;
接着的第T+2行有D个数,表示草儿想去地方。
 

Output
输出草儿能去某个喜欢的城市的最短时间。
 

Sample Input
6 2 31 3 51 4 72 8 123 8 44 9 129 10 21 28 9 10
 

Sample Output
9
 

Author
Grass
 

Source
RPG专场练习赛
 
思路:
 
          这道题和以前做的题唯一的不同就是给你的起点和终点的个数不是一个了,让你选一个起点到其中一个终点之间距离最短的路,输出最小的长度!所以你要遍历所有的起点到所有的终点的距离,选择一个最短的距离,将其输出!
 
          并且这道题的点的范围也没有给你,所以你要通过标胶来确定一个范围,然后才能用迪杰特斯拉算法!
 
代码:
 
#include <stdio.h>#include <string.h>#include <algorithm>using namespace std;#define INF 0x3f3f3f3fint map[1005][1005];int dis[1005];int vis[1005];int T,S,D;int x[1005];int y[1005];int z1,z2;void init(){int a,b,c;z1=INF,z2=0;memset(map,INF,sizeof(map));for(int i=1;i<=T;i++){scanf("%d%d%d",&a,&b,&c);z1=z1>a?a:z1;//最小的点 z1=z1>b?b:z1;z2=z2>a?z2:a;// 最大的点! z2=z2>b?z2:b;if(c<map[a][b])//要是重复输入一条路,要选花费时间小的!    map[a][b]=map[b][a]=c;}for(int i=1;i<=S;i++)   scanf("%d",&x[i]);for(int i=1;i<=D;i++)scanf("%d",&y[i]);}void dijkstra(int x){memset(vis,0,sizeof(vis));for(int i=z1;i<=z2;i++){dis[i]=map[x][i];}dis[x]=0;vis[x]=1;int min,k; for(int i=z1;i<=z2;i++){min=INF;for(int j=z1;j<=z2;j++){if(!vis[j]&&dis[j]<min){min=dis[j];k=j;}}if(min==INF)//这是两个等号,一定不能忘!!!!!!!!! break;vis[k]=1;for(int j=z1;j<=z2;j++){if(!vis[j]&&dis[j]>dis[k]+map[k][j]){dis[j]=dis[k]+map[k][j];}}}} int main(){while(scanf("%d%d%d",&T,&S,&D)!=EOF){int min=INF;init();for(int i=1;i<=S;i++){dijkstra(x[i]);for(int j=1;j<=D;j++){  min=min>dis[y[j]]?dis[y[j]]:min;}}printf("%d\n",min);}return 0;} 

虚拟顶点的代码:
 
//迪杰斯特拉+虚拟顶点法 //起点虚拟为最小的点减1,终点虚拟为最大的点加1,起点和终点都是唯一的,直接迪杰斯特大就行了! #include <stdio.h>#include <string.h>#include <algorithm>using namespace std;#define INF 0x3f3f3f3fint m,S,D;int map[1005][1005];int vis[1005];int dis[1005];int tx,ty;void init(){memset(map,INF,sizeof(map));memset(dis,INF,sizeof(dis));int a,b,c;tx=INF,ty=0;for(int i=1;i<=m;i++){scanf("%d%d%d",&a,&b,&c);tx=tx>a?a:tx;tx=tx>b?b:tx;ty=ty>a?ty:a;ty=ty>b?ty:b;if(map[a][b]>c)   map[a][b]=map[b][a]=c;}for(int i=1;i<=S;i++){scanf("%d",&a);//只有给的起点和虚拟起点距离为0,其他的点和起点的距离为INF     dis[a]=map[tx-1][a]=map[a][tx-1]=0;//要么写成双向边,要么写成map[tx-1][a]=0; }for(int j=1;j<=D;j++){scanf("%d",&a);//只有终点和虚拟终点之间的距离为0,其他的点和终点的距离为INF map[ty+1][a]=map[a][ty+1]=0;//这一点记住不要写成map[ty+1][a],这样是错的! }//要么写成双向边,要么写成map[a][ty+1]=0; }void dij(){memset(vis,0,sizeof(vis));int min,k;    for(int i=tx;i<=ty+1;i++)    {    min=INF;    for(int j=tx;j<=ty+1;j++)    {    if(!vis[j]&&min>dis[j])    {    min=dis[j];    k=j;    }    }    if(min==INF)    {    break;    }    vis[k]=1;    for(int j=tx;j<=ty+1;j++)    {    if(!vis[j]&&dis[j]>dis[k]+map[k][j])    {    dis[j]=dis[k]+map[k][j];    }    }    }    printf("%d\n",dis[ty+1]);}int main(){while(scanf("%d%d%d",&m,&S,&D)!=EOF){init();    dij();}return 0;}

0 0