长沙学院20级训练赛-原魔题解

链接:登录—专业IT笔试面试备考平台_牛客网
来源:牛客网

题目描述

众所周知,原魔是全宇宙最好的游戏。最近原魔出了一个策划模拟器,许多魔鬼策划在里面疯狂彰显才能,尽情的虐待旅行者。有这么一个萌新策划,她设置出了一个简单的地图,该地图有n个房间,她给每两个房间之间建了一条通道,该通道可以双向同行,但她觉得这样太简单了,决定加大难度,于是,她就拆掉了其中一些路,并想把终点设置在离起点最远的一间房间里,但她不知道那个最远,于是她向你求助,她告诉你了起点在哪个房间以及她拆掉了那些路,现在请你告诉她每个房间到起点的距离,并且告诉他哪个房间离起点最远,如果某个房间不能到达则输出-1。

输入描述:

第一行输入两个整数n,m,分别代表房间数,拆除的通道数。(n<=2e4,m<=1e5)

第二行输入一个整数S,表示起点房间的编号。(S∈[1,n])

第三行开始m行,每行两个整数a,b,表示房间a与房间b之间的通道被拆除了。(a,b∈[1,n],且a≠b)

输出描述:

输出共两行,第一行输出n个整数,表示每个房间到起点的距离,第二行一个整数,表示离起点最远的那个房间,如果最远的房间有多个,输出编号最小的那个。

示例1

输入

4 2 1 1 4 2 4

4 2
1
1 4
2 4

输出

0 1 1 2 4

0 1 1 2
4

解题思路:

通过本题的描述,很容易看出就是一个简单的bfs能解决的问题,但题目给的是一个补图,要想跑bfs就得建出正图,而建正图的复杂度是O(n^2),有亿点高,题目给的n的范围是2e4,要建正图绝对是超时了,这时我们发现,题目给的m很小,说明补图很小,既然这样,为什么不在补图上跑bfs呢?那又要怎么在补图上bfs呢?在这里我们要用到STL中的set,用set来维护图中还有那些点没跑到,在跑到这个点时,把与这个点在补图中有边的点放到未跑到的点集中,剩下的就是与之相连的点了,接下来就是正常的bfs就行了。

过题代码:

#include<bits/stdc++.h>
using namespace std;
#define Inf 1e9+7
const int N = 2e4 + 10;
const int M = 1e5 + 10;

int n, m;
int S, T;
int e[M], w[M], ne[M], h[N], idx;
int A[N];
int dis[N];
int q[N];
bitset<N>vis;

void add(int a, int b) {
    e[idx] = b;
    ne[idx] = h[a];
    h[a] = idx++;
}

void bfs() {
    int hh = 0, tt = 0;
    q[0] = S;
    set<int>s1, s2;
    for (int i = 1;i <= n;i++) {
        if (i != S) {
            s1.insert(i);
        }
    }
    while (hh <= tt) {
        int t = q[hh++];
        for (int i = h[t];~i;i = ne[i]) {
            int y = e[i];
            s1.erase(y);
            s2.insert(y);
        }
        for (set<int>::iterator it = s1.begin();it != s1.end();it++) {
            if (vis[*it]) {
                continue;
            }
            vis[*it] = 1;
            dis[*it] = dis[t] + 1;
            q[++tt] = *it;
        }
        s1.swap(s2);
        s2.clear();
    }
}

int main() {
        memset(dis, Inf, sizeof(dis));
        vis.reset();
        memset(h, -1, sizeof(h));
        idx = 0;
        scanf("%d %d", &n, &m);
        scanf("%d", &S);
        while (m--) {
            int a, b;
            scanf("%d %d", &a, &b);
            add(a, b);
            add(b, a);
        }
        dis[S] = 0;
        bfs();
        int ma = -1;
        int x = S;
        for (int i = 1;i <= n;i++) {
            if (dis[i] >= Inf) {
                printf("-1 ");
            }
            else {
                printf("%d ", dis[i]);
                if (ma < dis[i]) {
                    ma = dis[i];
                    x = i;
                }
            }
        }
        printf("\n%d\n", x);
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值