【BFS】Codeforce 1283D Christmas Trees

继续撸题中…

一、题目大意

题目的大致意思是,在无限长的坐标轴上,有一些圣诞树,坐标由X数组给出,然后有一些人想尽可能的离树近一点,所以题目要求求出一个数组y,表示对应人坐在坐标轴的位置,并且满足所有人距离他最近的圣诞树的距离和最小,题目会给出圣诞树和人的数目,也就是两个数组的长度。

注意,同一个坐标轴位置不能同时有两个物体(both for trees and people)

可能用文字叙述不是很清楚,下面给出题目提供的公式。
在这里插入图片描述
其中xi表示各个圣诞树的位置(题目给定),yi表示各个人的位置(需要求解)。

二、题目思路以及AC代码

做完这道题我觉得自己想掐死自己,看到这道题,很自然的就要想,要怎么选位置才能满足条件呢?肯定是找到每个圣诞树的位置,然后挨着圣诞树去填人就好了。比如题目给的样例

2 6
1 5

那么圣诞树的位置是1和5,要求我们安排6个人的位置,那肯定是先填0,2,4,6,因为这几个位置都是距离最近的圣诞树是1的位置,然后接下来找距离最近圣诞树是2的位置,以此类推。

这时候,我就开始犯糊涂了,首先想到的居然不是BFS,我首先想建立两个数组mLeft 和 mRight,分别存每个圣诞树左右两边的坐标,然后直接按照上述的过程模拟即可,但是会TLE,我琢磨为啥呢,因为我第一次遍历O(n)找到了所有距离为1的,第二次遍历O(n)找到了所有距离为2的,所以最后最大距离是多少,我的复杂度就是最大距离乘n,这无疑浪费了很多时间。

和我一开始的想法做对比,你就会发现BFS的时间节省在了哪里。每次不需要再重新遍历,因为queue里面已经存储了。不要说这些你早就知道,因为我也知道,跳出那个思维圈的时候我就发现,这tm就是一道BFS模板题,哭辽,花时间买教训。

下面给出AC代码,顺便也给出一开始我用辅助数组TLE的代码吧,留个纪念:

BFS AC代码:

/*
 * Codeforce 1283D: 
 * @ Author:    Johnson
 * @ Date:      2020.1.2
 */

#include <iostream>
#include <queue>
#include <vector>
#include <map>
#define MAXN 200010
using namespace std;

struct Point {
    int x;
    int diff;
};

int dx[2] = {-1, 1};

int n, m;
map<int, bool> mm;

int main() {

    cin >> n >> m;

    queue<Point> q;
    for (int i=0;i<n;i++) {
        Point p;
        cin >> p.x;
        p.diff = 0;
        q.push(p);
        mm[p.x] = true;
    }

    vector<int> res;
    int cnt = 0;
    long long ans = 0;
    bool finish = false;
    while(!q.empty() && !finish) {
        Point cur = q.front();  q.pop();

        for (int i=0;i<2;i++) {
            int nx = cur.x + dx[i];
            if (mm.find(nx) != mm.end()) continue;

            Point p;
            p.x = nx;
            p.diff = cur.diff + 1;
            res.push_back(nx);
            q.push(p);
            mm[nx] = true;
            cnt++;
            ans += p.diff;

            if (cnt >= m) {
                finish = true;
                break;
            }
        }
    }

    cout << ans << endl;
    for (int i=0;i<cnt;i++) {
        cout << res[i] << " ";
    }
    cout << endl;

    // system("pause");
    return 0;
}

辅助数组 TLE代码:

/*
 * Codeforce 1283D:
 * @ Author:    Johnson
 * @ Date:      2020.1.2
 */

#include <iostream>
#include <vector>
#include <algorithm>
#define MAXN 200010
using namespace std;

int n, m;
int trees[MAXN];
int mLeft[MAXN], mRight[MAXN];
bool vis_l[MAXN], vis_r[MAXN];

void init() {
    for (int i=0;i<MAXN;i++) {
        mLeft[i] = 0;
        mRight[i] = 0;
        vis_l[i] = true;
        vis_r[i] = true;
    }
}

int main() {

    init();

    cin >> n >> m;

    for (int i=0;i<n;i++) {
        cin >> trees[i];
    }
    sort(trees, trees+n);

    for (int i=0;i<n;i++) {
        mLeft[i] = trees[i] - 1;
        mRight[i] = trees[i] + 1;
    }

    for (int i=0;i<(n - 1);i++) {
        if (mLeft[i+1] < mRight[i]) {
            vis_l[i+1] = false;
            vis_r[i] = false;
        }
        else if (mLeft[i+1] == mRight[i]) {
            vis_l[i+1] = false;
        }
    }

    vector<int> res;
    int num = 0;
    bool finish = false;
    long long ans = 0;
    int diff = 1;

    while (true) {
        for (int i=0;i<n;i++) {
            if (vis_l[i]) {
                res.push_back(mLeft[i]);
                num++;
                mLeft[i]--;
                ans += diff;
            }
            if (num >= m) break;
            if (vis_r[i]) {
                res.push_back(mRight[i]);
                num++;
                mRight[i]++;
                ans += diff;
            }
            if (num >= m) break;
        }

        if (num >= m) break;
        
        diff++;
        for (int i=0;i<(n - 1);i++) {
            if (!vis_l[i+1] && !vis_r[i]) continue;
            if (mLeft[i+1] < mRight[i]) {
                vis_l[i+1] = false;
                vis_r[i] = false;
            }
            else if (mLeft[i+1] == mRight[i]) {
                vis_l[i+1] = false;
            }
        }
    }

    cout << ans << endl;
    for (int i=0;i<num;i++) {
        cout << res[i] << " ";
    }
    cout << endl;

    // system("pause");
    return 0;
}

如果有问题,欢迎大家留言!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值