FZU - 2261 Problem 2261 浪里个浪

Problem Description

TonyY是一个喜欢到处浪的男人,他的梦想是带着兰兰姐姐浪遍天朝的各个角落,不过在此之前,他需要做好规划。

现在他的手上有一份天朝地图,上面有n个城市,m条交通路径,每条交通路径都是单行道。他已经预先规划好了一些点作为旅游的起点和终点,他想选择其中一个起点和一个终点,并找出从起点到终点的一条路线亲身体验浪的过程。但是他时间有限,所以想选择耗时最小的,你能告诉他最小的耗时是多少吗?

 Input

包含多组测试数据。

输入第一行包括两个整数n和m,表示有n个地点,m条可行路径。点的编号为1 - n。

接下来m行每行包括三个整数i, j, cost,表示从地点i到地点j需要耗时cost。

接下来一行第一个数为S,表示可能的起点数,之后S个数,表示可能的起点。

接下来一行第一个数为E,表示可能的终点数,之后E个数,表示可能的终点。

0<S, E≤n≤100000,0<m≤100000,0<cost≤100。

 Output

输出他需要的最短耗时。

 Sample Input

4 41 3 11 4 22 3 32 4 42 1 22 3 4

 Sample Output

1

这是一道多源最短路,比赛的时候想要遍历所有的起点和终点,感觉会超,就没有打,下来看了题解才知道要建立一个超级原点和超级汇点,建好图后基本就是个裸的最短路。

将所有的起点都和0点建一条权边为0的边,这样从起点到点n的距离和点0到原点的距离是相同的,此时点0就是一个超级原点,终点也是一样,将所有的终点和点n+1建立一条权值为0的边。

然后跑一边从点0到点n+1的最短路就是所求了。

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define N 200005
int u[N],v[N],w[N],book[N],dis[N],first[N],nex[N],que[N];
int main()
{
    int n,m,x,y,o,t1,t2,t3;
    int inf=99999999;
    while(~scanf("%d %d",&n,&m))
    {
        memset(first,-1,sizeof(first));
        memset(que,0,sizeof(que));
        int k=1;
        for(int i=1;i<=m;i++)
        {
            scanf("%d %d %d",&t1,&t2,&t3);
            u[k]=t1;
            v[k]=t2;
            w[k]=t3;
            nex[k]=first[u[k]];
            first[u[k]]=k;
            k++;
        }
        scanf("%d",&x);
        for(int i=1;i<=x;i++)//建立从0到所有起点的权值为0的边
        {
            scanf("%d",&o);
            u[k]=0;
            v[k]=o;
            w[k]=0;
            nex[k]=first[u[k]];
            first[u[k]]=k;
            k++;
        }
        scanf("%d",&y);
        for(int i=1;i<=y;i++)//建立所有终点到n+1的权值为0的边
        {
            scanf("%d",&o);
            u[k]=o;
            v[k]=n+1;
            w[k]=0;
            nex[k]=first[u[k]];
            first[u[k]]=k;
            k++;
        }
        for(int i=0;i<=n+1;i++)
        {
            book[i]=0;
            dis[i]=inf;
        }
        book[0]=1;
        dis[0]=0;
        int head=1,tail=1;
        que[tail]=0;
        tail++;
        while(head<tail)//跑从0到n+1的最短路
        {
            int k=first[que[head]];
            while(k!=-1)
            {
                if(dis[v[k]]>dis[u[k]]+w[k])
                {
                    dis[v[k]]=dis[u[k]]+w[k];
                    if(book[v[k]]==0)
                    {
                        que[tail]=v[k];
                        tail++;
                        book[v[k]]=1;
                    }
                }
                k=nex[k];
            }
            book[que[head]]=0;
            head++;
        }
        printf("%d\n",dis[n+1]);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41925919/article/details/80263187
今日推荐