CCF201409-4 最优配餐(BFS)

传送门:CCF201409-4 最优配餐

一道很神奇的BFS题(蒟蒻的眼光)。题意大概是有m家门店,分别点了ci份单的k位顾客以及d个障碍物,骑手每携带一份外卖走一个单位花费一元钱,问m家门店该怎么分配配送任务使得总费用最少,当然,只需要输出最少的总费用。

身为一个蒟蒻,最开始我对每家分店都进行了一次BFS,超时了,很难受。不知该如何是好的我按捺不住偷代码的欲望,不小心瞥到了“所有分店同时BFS”的字样,灵机一动,一个字母都还没偷成的我关掉了网页,开始重构代码,然后就AC了...

值得注意的是,一个坐标可能有多位顾客,所以在读入的时候,若该坐标已有订单,就把新增的订单数加到原有的订单数上,然后将这两位顾客视作一位,就方便许多了。

然后就是一个常用的小技巧,已访问过的点会在vis数组中标记,同样的,我们可以把分店与不可经过的点标记进vis数组,这样代码就会更加简洁与清晰。

#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 1e3+10;
struct node
{
    int x, y, t;
    node(int X, int Y, int T): x(X), y(Y), t(T) {}
};
int n, m, k, d, K;
int g[maxn][maxn], vis[maxn][maxn];
int dir[4][2] = {1, 0, -1, 0, 0, 1, 0, -1};
ll ans = 0; //会爆int,应该使用long long
queue <node> q;

void read()
{
    cin >> n >> m >> k >> d;
    for(int i = 0; i < m; ++i)
    {
        int x, y;
        cin >> x >> y;
        vis[x][y] = 1;
        q.push(node(x, y, 0)); //把每个分店都预先放进队列中
                               //这样bfs的时候,它们可以共用一个vis数组
                               //可以节省大量时间,就避免了超时
    }
    for(int i = 0; i < k; ++i)
    {
        int x, y, c;
        cin >> x >> y >> c;
        if(g[x][y])
            g[x][y] += c;
        else
        {
            g[x][y] = c;
            K++;
        }
    }
    for(int i = 0; i < d; ++i)
    {
        int x, y;
        cin >> x >> y;
        vis[x][y] = 1;
    }
}

bool isLegal(int X, int Y, int i)
{
    int x = X+dir[i][0], y = Y+dir[i][1];
    if(x < 1 || x > n || y < 1 || y > n)
        return false;
    if(vis[x][y])
        return false;
    return true;
}

void bfs()
{
    while(!q.empty())
    {
        node cur = q.front();
        q.pop();
        if(g[cur.x][cur.y])
        {
            ans += cur.t*g[cur.x][cur.y];
            if(!(--K)) //所有订单配送完毕
                return;
        }

        for(int i = 0; i < 4; ++i)
            if(isLegal(cur.x, cur.y, i))
            {
                q.push(node(cur.x+dir[i][0], cur.y+dir[i][1], cur.t+1));
                vis[cur.x+dir[i][0]][cur.y+dir[i][1]] = 1;
            }
    }
}

void solve()
{
    bfs();
    cout << ans;
}

int main()
{
    read();
    solve();
    return 0;
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值