HDU Today

来源:互联网 发布:学校结核病管理网络 编辑:程序博客网 时间:2024/06/05 03:47
经过锦囊相助,海东集团终于度过了危机,从此,HDU的发展就一直顺风顺水,到了2050年,集团已经相当规模了,据说进入了钱江肉丝经济开发区500强。这时候,XHD夫妇也退居了二线,并在风景秀美的诸暨市浬浦镇陶姚村买了个房子,开始安度晚年了。
这样住了一段时间,徐总对当地的交通还是不太了解。有时很郁闷,想去一个地方又不知道应该乘什么公交车,在什么地方转车,在什么地方下车(其实徐总自己有车,却一定要与民同乐,这就是徐总的性格)。
徐总经常会问蹩脚的英文问路:“Can you help me?”。看着他那迷茫而又无助的眼神,热心的你能帮帮他吗?
请帮助他用最短的时间到达目的地(假设每一路公交车都只在起点站和终点站停,而且随时都会开)。
Input
输入数据有多组,每组的第一行是公交车的总数N(0<=N<=10000);
第二行有徐总的所在地start,他的目的地end;
接着有n行,每行有站名s,站名e,以及从s到e的时间整数t(0<t<100)(每个地名是一个长度不超过30的字符串)。
note:一组数据中地名数不会超过150个。
如果N==-1,表示输入结束。
Output
如果徐总能到达目的地,输出最短的时间;否则,输出“-1”。
Sample Input
6xiasha westlakexiasha station 60xiasha ShoppingCenterofHangZhou 30station westlake 20ShoppingCenterofHangZhou supermarket 10xiasha supermarket 50supermarket westlake 10-1
Sample Output
50Hint:The best route is:xiasha->ShoppingCenterofHangZhou->supermarket->westlake虽然偶尔会迷路,但是因为有了你的帮助**和**从此还是过上了幸福的生活――全剧终――

邻接矩阵的dijkstra

#include<stdio.h>#include<iostream>#include<cstring>#include<map>using namespace std;/*这种方式还是比较可以接受的,就是占用的空间比较大,是直接进行矩形的距离赋值,如果比较大就不太好了但是操作比较简单,但是有冗余的操作,就是那个查找,浪费了很多时间而我们用队列来优化的话,我们就不会再去找这些vis[]的了,但是用优先队列,很麻烦,需要写的东西实在太多,不太好*/const int maxn=20010;//因为是双向边,所以我们需要是T*2const int INF=0x3f3f3f3f;int dis[160];int vis[160];int len[200][200];int n;map<string,int> station;//将车站编号string st,ed;int dijkstra(int st_,int end_){    memset(vis,0,sizeof(vis));    for(int i=1;i<=end_;i++)        dis[i]=INF;    dis[st_]=0;//自己到自己的距离就是0    for(int i=st_;i<=end_;i++)    {        int j,m;        int temp=INF;        for( j=st_;j<=end_;j++)        {            if(!vis[j]&&dis[j]<temp)//还没有在合并的里面 都是找最近的那个点来松弛            {                temp=dis[j];                m=j;            }        }        vis[m]=1;//标记这个最小值点        if(temp==INF)//找不到能松弛的了,那我们就可以提前退出            break;        for(int k=st_;k<=end_;k++)//对所有的点进行松弛操作        {            if(dis[k]>temp+len[m][k])                dis[k]=temp+len[m][k];        }    }    return dis[station[ed]];}int main(){    while(~scanf("%d",&n))    {        int it=1;        if(n==-1) break;        station.clear();//清空映射        memset(len,INF,sizeof(len));        cin>>st>>ed;        if(!station[st])            station[st]=it++;        if(!station[ed])            station[ed]=it++;        for(int i=1;i<=n;i++)        {            string u,v;int w;            cin>>u>>v>>w;            if(!station[u])//之后没有出现的这样写就好了,感觉还是很好的,就是一个对地名的编号                station[u]=it++;            if(!station[v])                station[v]=it++;            int x=station[u],y=station[v];            len[x][y]=len[y][x]=w;//直接赋值权重        }        if(station[st]==station[ed])        {              printf("0\n");              continue;        }        int ans=dijkstra(1,it-1);        if(ans==INF)            printf("-1\n");        else            printf("%d\n",ans);    }    return 0;}

前向星的dijkstra

#include<bits\stdc++.h>using namespace std;const int maxn=20010;//因为是双向边,所以我们需要是T*2const int INF=0x3f3f3f3f;int dis[maxn];int vis[maxn];int head[maxn];map<string,int> station;//将车站编号int n;int cnt;string st,ed;struct edge{    int v,w;    int next;}Edge[maxn];void add_edge(int u,int v,int w){    Edge[cnt].v=v;    Edge[cnt].w=w;    Edge[cnt].next=head[u];    head[u]=cnt++;}typedef struct node{    int point,distance;    node(){}    node(int _point,int _distance){point=_point,distance=_distance;}    bool operator < (const node& other)const    {        return distance >other.distance;    }}Node;int dijkstra(int s){    for(int i=1;i<=n;i++)        dis[i]=INF;    memset(vis,0,sizeof(vis));    Node now,next;    dis[s]=0;    priority_queue<Node> pq;    pq.push(node(s,dis[0]));    while(pq.size())    {        now=pq.top();        pq.pop();     //   if(vis[now.point])//怎么会在最短之后又进入呢,事实证明这里没有必要再去写这个vis[],我们都是从小到大去松弛,所以不会出现后面更小的情况     //        continue;     //   vis[now.point]=1;        for(int i=head[now.point];i!=-1;i=Edge[i].next)        {            int to=Edge[i].v;//从当前点出发的点            if(dis[to]>dis[now.point]+Edge[i].w)            {                dis[to]=dis[now.point]+Edge[i].w;             //   if(to==station[ed])             //       return dis[station[ed]];                pq.push(node(to,dis[to]));            }        }    }    return dis[station[ed]];}int main(){    while(~scanf("%d",&n))    {        cnt=0;int it=1;        memset(head,-1,sizeof(head));        memset(Edge,0,sizeof(Edge));        if(n==-1) break;        station.clear();//清空映射        cin>>st>>ed;        if(!station[st])            station[st]=it++;        if(!station[ed])            station[ed]=it++;        for(int i=1;i<=n;i++)        {            string u,v;int w;            cin>>u>>v>>w;            if(!station[u])//之后没有出现的这样写就好了,感觉还是很好的,就是一个对地名的编号                station[u]=it++;            if(!station[v])                station[v]=it++;            add_edge(station[u],station[v],w);//对边进行记录            add_edge(station[v],station[u],w);//        }        if(station[st]==station[ed])//因为他要是同一个点的话,我们是不能重复访问一个点的,所以得把这种情况排除        {              printf("0\n");              continue;        }        int ans=dijkstra(1);//传入起点,距离就是指的距离1的距离了        if(ans==INF)            printf("-1\n");        else            printf("%d\n",ans);    }    return 0;}

前向星的spfa

#include<bits\stdc++.h>using namespace std;/*发现还是spfa这种算法好用,一个是代码量比较少,再就是还能判断有没有负环功能比较强大,主要是那个digkstra算法,用优先队列来实现实在是太复杂了,还得造一个节点结构体,还得写比较函数实在是麻烦*/const int maxn=20010;//因为是双向边,所以我们需要是T*2const int INF=0x3f3f3f3f;int dis[maxn];int vis[maxn];int head[maxn];map<string,int> station;//将车站编号int n;int cnt;string st,ed;struct edge{    int v,w;    int next;}Edge[maxn];void add_edge(int u,int v,int w){    Edge[cnt].v=v;    Edge[cnt].w=w;    Edge[cnt].next=head[u];    head[u]=cnt++;}int spfa(int s){    int time[maxn];    memset(time,0,sizeof(time));//检测访问的次数    memset(vis,0,sizeof(vis));//是否访问过    for(int i=1;i<=n;i++)        dis[i]=INF;    dis[s]=0;vis[s]=1;time[s]++;    queue<int> q;    q.push(s);    while(q.size())    {        int now=q.front();        q.pop();        vis[now]=0;//之后我们还能放回来,记住        for(int i=head[now];i!=-1;i=Edge[i].next)        {            int to=Edge[i].v;            if(Edge[i].w+dis[now]<dis[to])            {                dis[to]=Edge[i].w+dis[now];                if(!vis[to])//只有松弛成功并且现在没有在队列里面的才可以进入队列                {                   vis[to]=1;                   time[to]++;                   q.push(to);                   if(time[to] >= n)//存在负环,没有最小的路径                     return -1;                }            }        }    }    return dis[station[ed]];}int main(){    while(~scanf("%d",&n))    {        cnt=0;int it=1;        memset(head,-1,sizeof(head));        memset(Edge,0,sizeof(Edge));        if(n==-1) break;        station.clear();//清空映射        cin>>st>>ed;        if(!station[st])            station[st]=it++;        if(!station[ed])            station[ed]=it++;        for(int i=1;i<=n;i++)        {            string u,v;int w;            cin>>u>>v>>w;            if(!station[u])//之后没有出现的这样写就好了,感觉还是很好的,就是一个对地名的编号                station[u]=it++;            if(!station[v])                station[v]=it++;            add_edge(station[u],station[v],w);//对边进行记录            add_edge(station[v],station[u],w);//        }        if(station[st]==station[ed])//因为他要是同一个点的话,我们是不能重复访问一个点的,所以得把这种情况排除        {              printf("0\n");              continue;        }        int ans=spfa(1);//传入起点,距离就是指的距离1的距离了               if(ans==INF)            printf("-1\n");        else            printf("%d\n",ans);    }    return 0;}