下片 题解(最短路+超级源点)

题目描述

为了提高服务器的耐受能力,很多流量大的网站都会架设多台服务器,而互联网的路由能找到线路最短的一台服务器。 现在UOI想要下片,他有好多台电脑,又有好多服务器可以提供下载。UOI将给你一个网络图,告诉你点点之间的线路长度,问最短的线路长是多少,以及选择的那台用来下载的电脑和被选的服务器的编号。 如果有多台电脑/服务器之间连线都是最短线路,输出电脑编号最小的;如果还有多种选择,输出服务器编号最小的。

输入格式

第一行n,m,表示总格有n个点,m条网络连线 接下来m行,表示每条网络连线所连接的A、B点和线的长度。 接下来一个数T1,表示UOI有多少台电脑。 下一行T1个数,表示UOI每台电脑的编号。 接下来一个数T2,表示有多少台服务器。 下一行T2个数,表示每台服务器编号。

输出格式

三个数,分别是线路长度,UOI下载用的电脑,提供片的下载源

-------------------------------------------------------------------------------------------------------------------------

题意转化:给你一些源点和一些汇点,求一条连接源点和汇点的路径并且使得这条路径的长度最小。

使用n次spfa显然会TLE。这时候我们要引入一个概念:超级源点。意思是引入一个0号点,能连接所有源点,并且不影响原图,即长度为0。这样跑1次spfa就够。此题还要求输出源点和汇点,我们开一个pre数组,记录每个点的前驱即可(前驱指的是从哪个源点可以到达那里)。

代码中稍稍做了一点修改,本身思路与其相符。

#include<bits/stdc++.h>
using namespace std;
queue<int> q;
struct node
{
    int to,dis;
};
vector<node> v[100005];
int n,m,t1,t2,a[100005],vis[100005],pre[100005];
long long ans=9223372036854775807,dis[100005];
int ans1,ans2;
int main()
{
    memset(dis,0x3f,sizeof(dis));
    scanf("%d%d",&n,&m);
    for (int i=1;i<=m;i++)
    {
        int u,to,d;
        scanf("%d%d%d",&u,&to,&d);
        v[u].push_back((node){to,d});
        v[to].push_back((node){u,d});
    }
    scanf("%d",&t1);
    for (int i=1;i<=t1;i++) scanf("%d",&a[i]);
    sort(a+1,a+t1+1);
    scanf("%d",&t2);
    int t;
    for (int i=1;i<=t2;i++) scanf("%d",&t),pre[t]=t,vis[t]=1,dis[t]=0,q.push(t);
    while(!q.empty())
    {
        int now=q.front();q.pop();vis[now]=0;
        for (int i=0;i<v[now].size();i++)
        {
            int to=v[now][i].to;
            if (dis[to]>dis[now]+v[now][i].dis)
            {
                pre[to]=pre[now];
                dis[to]=dis[now]+v[now][i].dis;
                if (!vis[to]) vis[to]=1,q.push(to);
             } 
        }
    }
    for (int i=1;i<=t1;i++)
        if (ans>dis[a[i]]) ans=dis[a[i]],ans1=a[i];
    printf("%ld %d %d",ans,ans1,pre[ans1]);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Invictus-Ocean/p/12454307.html
今日推荐