CF590C Three States

题目链接

题目

见链接。

题解

知识点:BFS。

这道题求连接三个国家的最短路径长度。如果枚举每个点进行bfs,显然不可行,换种思路,从三个国家开始分别进行bfs是可以的。

注意一开始初始化两个距离数组要无穷大 (0x7f/3 ,除三是因为防止加起来炸了)。

国家是个连通块,而连通块内部是不算路径长度的,那么一开始预处理把连通块内所有格子的步数全设为 \(0\),并直接入队,否则会超时

\(vis\) 数组记录状态是否访问过,因为步数都是恒定 \(1\) 的增量不需要考虑维护bfs扩展顺序,也不必考虑扩展的步数是否小于访问过的点的步数,因为时间线是有序的,这样可以直接用 \(vis\) 可以省一点时间。

当起点国家遇到国家的格子时,就不需要继续搜索了,因为国家内部是不算长度的,只需要用另外一个数组记录国家和国家之间的最短路径即可,当作直线连接国家的最短路径长度,不然会超时

其他情况都是国家之外的点到三个国家的距离,正常记录即可。

最后取三个国家每个与其他两个国家直线距离和(有国家和国家连通的特殊情况,这种情况直线最短)与场上不是国家的点到三个国家的距离和减2(因为国家之外的点,三个国家会多算两次这个点的距离,所以减二;而直线距离中间隔着国家,不会多算点)的最小值。

取直线距离最小值时候要注意,一定每个国家为起点的都看一下。因为比如三个国家在一直线上,顺序为 \(1,2,3\) ,显然 \(1\) 遇到 \(2\) 以后就停了,\(3\) 也一样,那么 \(1\)\(3\) 的距离就是无穷大。但考虑 \(2\) ,则有通路 \(21\)\(23\) 。因此每个国家都要作为起点都看一下直线距离。

时间复杂度 \(O(?)\)

空间复杂度 \(O(nm)\)

代码

#include <bits/stdc++.h>

using namespace std;

int n, m;
char dt[1007][1007];
bool vis[1007][1007][3];
int d[1007][1007][3];
int D[3][3];
const int dir[4][2] = { {1,0},{-1,0},{0,1},{0,-1} };

struct node {
    int x, y;
};

void bfs(int id) {
    queue<node> q;
    for (int i = 0;i < n;i++) {
        for (int j = 0;j < m;j++) {
            if (dt[i][j] == id + '1') {
                d[i][j][id] = 0;
                q.push({ i,j });
            }
        }
    }

    while (!q.empty()) {
        node cur = q.front();
        q.pop();
        for (int i = 0;i < 4;i++) {
            int xx = cur.x + dir[i][0];
            int yy = cur.y + dir[i][1];
            if (xx < 0 || xx >= n || yy < 0 || yy >= m || dt[xx][yy] == '#' || vis[xx][yy][id]) continue;
            vis[xx][yy][id] = 1;
            if (dt[xx][yy] == '.') {
                d[xx][yy][id] = d[cur.x][cur.y][id] + 1;
                q.push({ xx, yy });
            }
            else {
                if (D[id][dt[xx][yy] - '1'] > 1e6)
                    D[id][dt[xx][yy] - '1'] = d[cur.x][cur.y][id];
            }
        }
    }
}

int main() {
    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    memset(d, 0x7f / 3, sizeof(d));
    memset(D, 0x7f / 3, sizeof(D));
    cin >> n >> m;
    for (int i = 0;i < n;i++) {
        for (int j = 0;j < m;j++) {
            cin >> dt[i][j];
        }
    }
    for (int i = 0;i < 3;i++) bfs(i);
    int ans = ~(1 << 31);
    for (int i = 0;i < 3;i++) {
        int sum = 0;
        for (int j = 0;j < 3;j++)
            if (i != j) sum += min(D[i][j], D[j][i]);
        ans = min(ans, sum);
    }
    for (int i = 0;i < n;i++) {
        for (int j = 0;j < m;j++) {
            if (dt[i][j] == '.') ans = min(ans, d[i][j][0] + d[i][j][1] + d[i][j][2] - 2);
        }
    }
    cout << (ans > 1e6 ? -1 : ans) << '\n';
    return 0;
}
posted @ 2022-07-16 20:34  空白菌  阅读(35)  评论(0编辑  收藏  举报