FZU - 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 4
1 3 1
1 4 2
2 3 3
2 4 4
2 1 2
2 3 4

Sample Output

1

Source

福州大学第十四届程序设计竞赛_重现赛

思路:第一次自己做的时候用spfa把每个点都遍历一遍,然后找每个点到终点的最短路。

#include<queue>
#include<algorithm>
#include<stdio.h>
#include<string.h>
using namespace std;
struct node
{
    int x, y, s;
} a[100010];
int first[100010], nextt[100010];
int n, m, e, w,ans;
int sta[100010], en[100010];
int dis[100010],book[100010];
queue<int>q;
void spfa(int x)
{
    q.push(x);
    memset(dis,0x3f,sizeof(dis));
    dis[x]=0;
    while(!q.empty())
    {

        x=q.front();
        book[x]=0;
        q.pop();
        int k=first[x];
        while(k>=0)
        {
            if(dis[a[k].y]>dis[a[k].x]+a[k].s)
            {
                dis[a[k].y]=dis[a[k].x]+a[k].s;
                if(!book[a[k].y])
                {
                    q.push(a[k].y);
                    book[a[k].y]=1;
                }
            }
            k=nextt[k];
        }
    }
}
int main()
{
    while(~scanf("%d%d", &n, &m))
    {
        ans=0x3f3f3f;
        memset(first, -1, sizeof(first));
        memset(nextt, -1, sizeof(nextt));
        for(int i = 0; i < m; i++)
        {
            scanf("%d%d%d", &a[i].x, &a[i].y, &a[i].s);
            nextt[i] = first[a[i].x];
            first[a[i].x] = i;
        }
        scanf("%d", &e);
        for(int i = 0; i < e; i++)
        {
            scanf("%d", &sta[i]);
        }
        scanf("%d", &w);
        for(int i = 0; i < w; i++)
        {
            scanf("%d",&en[i]);
        }
        for(int i=0;i<e;i++)
        {
            spfa(sta[i]);
            for(int i=0;i<w;i++)
            {
                ans=min(ans,dis[en[i]]);
            }
        }
        printf("%d\n",ans);
    }
}

正解:把0点设为集合起点,n+1为集合终点,0到所有起点距离为0,所有终点到n+1的终点为0.问题就转变成了找0到n+1的最短路。
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<queue>
#define M 100010
using namespace std;
int n,m;
struct node
{
    int x,y,s,nextt;
}a[M];
queue<int>q;
int heat[M],cut;
int dis[M],vis[M];
void add(int x,int y,int s)
{
    a[cut].y=y;
    a[cut].s=s;
    a[cut].nextt=heat[x];
    heat[x]=cut++;
}
void spfa()
{
    q.push(0);
    memset(vis,0,sizeof(vis));
    memset(dis,0x3f,sizeof(dis));
    dis[0]=0;
    int x,k;
    while(!q.empty())
    {
        x=q.front();
        q.pop();
        vis[x]=0;
        k=heat[x];
        while(k>=0)
        {
            if(dis[a[k].y]>dis[x]+a[k].s)
            {
                dis[a[k].y]=dis[x]+a[k].s;
                if(!vis[a[k].y])
                {
                    vis[a[k].y]=1;
                    q.push(a[k].y);
                }
            }
            k=a[k].nextt;
        }
    }
    printf("%d\n",dis[n+1]);
}
int main()
{
    int x,y,s;
    while(~scanf("%d%d",&n,&m))
    {
        memset(heat,-1,sizeof(heat));
        cut=0;
        for(int i=0;i<m;i++)
        {
            scanf("%d%d%d",&x,&y,&s);
            add(x,y,s);
        }
        scanf("%d",&m);
        while(m--)
        {
            scanf("%d",&x);
            add(0,x,0);
        }
        scanf("%d",&m);
        while(m--)
        {
            scanf("%d",&y);
            add(y,n+1,0);
        }
        spfa();
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_41380961/article/details/80262446