zoukankan      html  css  js  c++  java
  • cf 591 E.Three States 01bfs

    传送门

    有3个城市,'.'表示空地,可以用于建桥,'#'是城墙。
    然后求至少需要建几个桥才能使得3个城市连通。
    思路是用01bfs
    建立一个数组dis[k][i][j]表示从第k个城市出发到i,j至少要建筑几个桥。
    然后进行3次01bfs,因为'.'需要花费,权值是1,所以放在双端队列的尾部,其他放在双端队列的首部,每次都取双端队列的首部进行bfs
    最后遍历每个点,在3个城市都能到达的前提下。
    int now = dis[0][i][j] + dis[1][i][j] + dis[2][i][j] - 2 * (s[i][j] == '.');因为'.'算了3次,所以必须要剪掉2次。
    就是一种方案,求出最小方案就是答案。

    也可以用最短路去求出距离,但最短路的时间复杂度明显高了,对于权值只有0和1的情况下最好用01bfs,时间复杂度低一点

    #include <bits/stdc++.h>
    #define ll long long
    #define ld long double
    #define CASE int Kase = 0; cin >> Kase; for(int kase = 1; kase <= Kase; kase++)
    using namespace std;
    template<typename T = long long> inline T read() {
        T s = 0, f = 1; char ch = getchar();
        while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();}
        while(isdigit(ch)) {s = (s << 3) + (s << 1) + ch - 48; ch = getchar();} 
        return s * f;
    }
    #ifdef ONLINE_JUDGE
    #define qaq(...) ;
    #define qwq(c) ;
    #else
    #define qwq(a, b) for_each(a, b, [=](int x){cerr << x << " ";}), cerr << std::endl
    template <typename... T> void qaq(const T &...args) {
        auto &os = std::cerr;
        (void)(int[]){(os << args << " ", 0)...};
        os << std::endl;
    }
    #endif
    const int N = 1e3 + 5, M = 1e6 + 5, MOD = 1e9 + 7, CM = 998244353, INF = 0x3f3f3f3f; const ll linf = 0x7f7f7f7f7f7f7f7f;
    char s[N][N];
    int dis[4][N][N];
    struct Node{
        int x, y;
    };
    int dir[][2] = {1,0, -1,0, 0,1, 0,-1};
    void bfs01(int st, int sx, int sy, int n, int m){
        deque<Node> q;
        q.push_back(Node{sx, sy});
        dis[st][sx][sy] = 0;
        while(!q.empty()) {
            Node tmp = q.front(); q.pop_front();
            int x = tmp.x, y = tmp.y;
            for(int i = 0; i < 4; i++) {
                int xx = x + dir[i][0], yy = y + dir[i][1];
                if(xx < 1 || xx > n || yy < 1 || yy > m || s[xx][yy] == '#') continue;
                int nowdis = dis[st][x][y] + (s[xx][yy] == '.');
                if(nowdis < dis[st][xx][yy]) {
                    dis[st][xx][yy] = nowdis;
                    if(s[xx][yy] == '.') q.push_back(Node{xx, yy});
                    else q.push_front(Node{xx, yy});
                }
            }
        }
    }
    void solve(int kase){
        memset(dis, 0x3f, sizeof(dis));
        int n = read(), m = read(); 
        for(int i = 1; i <= n; i++) scanf("%s", s[i] + 1);
        for(int k = 1; k <= 3; k++) {
            int x = 0, y = 0;
            for(int i = 1; i <= n; i++) {
                for(int j = 1; j <= m; j++) {
                    if(s[i][j] == '0' + k) {
                        x = i, y = j;
                    }
                }
            }
            bfs01(k - 1, x, y, n, m);
        }
        int ans = -1;
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= m; j++) {
                if(dis[0][i][j] != INF && dis[1][i][j] != INF && dis[2][i][j] != INF) {
                    int now = dis[0][i][j] + dis[1][i][j] + dis[2][i][j] - 2 * (s[i][j] == '.');
                    if(ans == -1) ans = now;
                    else ans = min(ans, now);
                }
            }
        }
        printf("%d
    ", ans);
    }
    const bool ISFILE = 0, DUO = 0;
    int main(){
        clock_t start, finish; start = clock();
        if(ISFILE) freopen("/Users/i/Desktop/practice/in.txt", "r", stdin);
        if(DUO) {CASE solve(kase);} else solve(1);
        finish = clock(); 
        qaq("
    Time:", (double)(finish - start) / CLOCKS_PER_SEC * 1000, "ms
    ");
        return 0;
    }
    
    I‘m Stein, welcome to my blog
  • 相关阅读:
    sublime text3安装package control插件图文教程
    conda创建新环境
    常用的vscode插件安装
    数组合并组合
    内核软死锁
    Ubuntu分区格式化并挂载新增磁盘方法
    Linux如何列出svn一个文件夹下的所有文件
    C++ UTF-8和GBK相互转化
    Linux shell如何用正则表达式匹配分组数据
    如何对接jsoncpp?
  • 原文地址:https://www.cnblogs.com/Emcikem/p/14704527.html
Copyright © 2011-2022 走看看