29.安排超市(卡码网第一期模拟笔试)

29.安排超市(卡码网第一期模拟笔试)

题目描述

给定一个 n*n 的地图。地图是上下左右四联通的,但是不能斜向行走。
其中:
*代表障碍,不可通行;
.代表路,可以通行;
#代表房子。房子也是可以通行的。
现在需要在一些地方安排一些超市(不能安排在障碍物上,可以安排在路上或者房子上,超市也是可以通行的),每个房子至少可以到达一个超市。同时由于成本原因,超市的数量需要尽可能的少。
在超市数量最少的情况下,每个房子到达最近的超市的距离之和需要尽可能小。
你的任务是计算超市最少的数量,以及最小的距离之和。

输入

第一行包含一个正整数 n,代表地图的大小(1 <= n <= 50)。 接下来的 n 行,每行包含一个长度为 n 的字符串,表示整个地图。

输出

输出两个整数,用空格隔开。分别代表超市的最小数量、最小的距离之和。

样例输入

3
#.#
.**
*.#

样例输出

2 2

提示

下标从 0 开始,第一个超市安排的位置是(0,1),第二个超市安排的位置是(2,2)。 三个房子到超市的距离分别为1、1、0。这样可以使得三个房子都能到达超市,并且所需超市数量最少,总距离之和也最少。
注意:超市直接建在房子上距离为 0。如果没有房子,则不需要建超市。

题解1(C++版本)

#include<bits/stdc++.h>
using namespace std;

const int N = 53, INF = 1e9;

int n, min_market, min_dis;
char mp[N][N];
int dx[] = {1,0,-1,0};
int dy[] = {0,1,0,-1};
bool vis[N][N], v[N][N];

bool check(int x, int y){
    if(x < 1 || x > n || y < 1 || y > n || mp[x][y] == '*') return false;
    return true;
}
vector<pair<int, int>> points; //保存该连通分量中的所有可以不在障碍物上的点

void dfs(int x, int y){
    vis[x][y] = 1;
    points.push_back({x, y}); //将同一个连通分量中的点加入到一个集合中
    for(int i = 0; i < 4; i++) {
        int tx = x + dx[i];
        int ty = y + dy[i];
        if(!check(tx, ty) || vis[tx][ty]) continue;
        dfs(tx, ty);
    }
}

struct node{
    int x, y, step;
}tmp;
int bfs(int x, int y){ //获取以(x,y)为超市到该区域内所有房子的最小距离
    queue<node> q;
    memset(v, 0, sizeof v);
    q.push({x, y, 0});
    v[x][y] = 1;
    int dis = 0;
    while(!q.empty()) {
        tmp = q.front(); q.pop();
        if(mp[tmp.x][tmp.y] == '#') dis += tmp.step;
        for(int i = 0; i < 4; i++){
            int tx = tmp.x + dx[i];
            int ty = tmp.y + dy[i];
            if(!check(tx, ty) || v[tx][ty]) continue;
            q.push({tx, ty, tmp.step + 1});
            v[tx][ty] = 1;
        }
    }
    return dis;
}
int main(){
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) scanf("%s", mp[i] + 1);
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= n; j++){
            points.clear(); //清空上一个区域内的所有房子
            if(mp[i][j] == '#' && !vis[i][j]){
                min_market++; //连通分量数加1
                dfs(i, j);
                int cur_dis = INF;
                for(auto point : points){ //遍历该连通分量所有的点,找到一点到所有房子的最小距离
                    cur_dis = min(cur_dis, bfs(point.first, point.second));
                }
                min_dis += cur_dis;
            }
        }
    }
    printf("%d %d\n", min_market, min_dis);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值