zoukankan      html  css  js  c++  java
  • 【FZYZOJ】下片 题解(最短路+超级源点)

    题目描述

    为了提高服务器的耐受能力,很多流量大的网站都会架设多台服务器,而互联网的路由能找到线路最短的一台服务器。 现在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;
    }
  • 相关阅读:
    算法竞赛入门经典习题2-3 韩信点兵
    ios入门之c语言篇——基本函数——5——素数判断
    ios入门之c语言篇——基本函数——4——数值交换函数
    144. Binary Tree Preorder Traversal
    143. Reorder List
    142. Linked List Cycle II
    139. Word Break
    138. Copy List with Random Pointer
    137. Single Number II
    135. Candy
  • 原文地址:https://www.cnblogs.com/Invictus-Ocean/p/12454307.html
Copyright © 2011-2022 走看看