【kuangbin】专题一 简单搜索

【kuangbin】专题一 简单搜索

https://www.acwing.com/activity/content/90/
目录:

1. 棋盘问题

普通dfs问题,注意回溯。
dfs问题就是每种方案都try一下,一直莽到头,然后再挨个回头(回溯)

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
int n, k;
ll cnt, res;
char a[10][10];
bool vis[10];

void dfs (int x) {
    if (res == 0)       {cnt ++; return ;}
    if (x == n + 1)     return ;
    for (int i = 1; i <= n; i ++) {
        if (vis[i] || a[x][i] == '.')  continue;
        vis[i] = true;
        res --;
        dfs (x + 1);
        vis[i] = false;
        res ++;
    }
    dfs (x + 1);
}

int main () {
    while (cin >> n >> k, (n+1)||(k+1)) {
        memset (vis, false, sizeof vis);
        cnt = 0, res = k;
        for (int i = 1; i <= n; i ++)
            for (int j = 1; j <= n; j ++)
                cin >> a[i][j];
        dfs (1);
        cout << cnt << endl;
    }
}

2. 地牢大师

简单bfs,不同的是坐标是3维的,开三维数组即可

#include <bits/stdc++.h>

using namespace std;
const int N = 105;
char a[N][N][N];
int d[N][N][N];
int l, r, c, sx, sy, sz;

int dx[] = {0, 0, 0, 0, -1, 1};
int dy[] = {1, 0, -1, 0, 0, 0};
int dz[] = {0, 1, 0, -1, 0, 0};

struct Node {
    int x, y, z;
};

bool Range (int x, int y, int z) {
    if (x > l || x <= 0 || y > r || y <= 0 || z > c || z <= 0)
        return false;
    return true;
}

void bfs () {
    memset (d, 0x3f, sizeof d);
    queue <Node> q;
    q.push ({sx, sy, sz});
    d[sx][sy][sz] = 0;

    while (!q.empty ()) {
        auto t = q.front ();
        q.pop();
        int x = t.x, y = t.y, z= t.z;

        for (int i = 0; i < 6; i ++) {
            int xx = x + dx[i], yy = y + dy[i], zz = z + dz[i];
            if (!Range (xx, yy, zz) || d[xx][yy][zz] != 0x3f3f3f3f || a[xx][yy][zz] == '#') continue;
            d[xx][yy][zz] = d[x][y][z] + 1;
            q.push ({xx, yy, zz});
            if (a[xx][yy][zz] == 'E') {
                cout << "Escaped in " << d[xx][yy][zz] << " minute(s)." << endl;
                return ;
            }
        }
    }
    cout << "Trapped!" << endl;
}

int main () {
    while (cin >> l >> r >> c, l || r || c) {
        for (int i = 1; i <= l; i ++)
            for (int j = 1; j <= r; j ++)
                for (int k = 1; k <= c; k ++) {
                    cin >> a[i][j][k];
                    if (a[i][j][k] == 'S')  sx =  i, sy = j, sz = k;
                }
                    
        bfs ();

    }

}

3. 抓住那头牛

也是套路化的bfs,把三种操作视为状态,存入dx[]即可

#include <bits/stdc++.h>

using namespace std;
const int N = 1e5 + 5;
int d[N];
int st, ed;

bool Range (int x) {
    if (x < 0 || x > 1e5)   return false;
    return true;
}

void bfs () {
    memset (d, 0x3f, sizeof d);
    d[st] = 0;
    queue <int> q;
    q.push (st);

    while (!q.empty ()) {
        int x = q.front ();
        q.pop();

        int dx[] = {-1, 1, x};
        for (int i = 0; i < 3; i ++) {
            int xx = x + dx[i];
            if (!Range (xx) || d[xx] != 0x3f3f3f3f) continue;
            d[xx] = d[x] + 1;
            q.push (xx);
            if (xx == ed) {
                cout << d[xx] << endl;
                return ;
            }
        }
    }
}

int main () {
    cin >> st >> ed;
    if (st == ed) {
        cout << 0 << endl;
        return 0;
    }
    bfs ();

}


//bfs经典模型

4. 翻转

个人觉得初接触有点难理解
逻辑:枚举每一种方案,第一行只能靠改变自身;然后依次通过后面的来改变前面的,最后check最后一行是否满足条件(满足则记录为一种方案)
。。。感觉还有些抽象,我建议多模拟几遍代码,代入数据在草稿纸上演算。。因为我也看了好多遍的

对了,还涉及一些位运算的知识,记得滚回去复习

#include <bits/stdc++.h>

using namespace std;
typedef pair<int, int> pii;
const int N = 20;
int n, m;
char a[N][N], b[N][N];//备用图(在这上面改动) 原图(不变的)
int ans[N][N], tmp[N][N]; //最终方案 临时方案
int dx[] = {0, 1, 0, -1, 0}, dy[] = {0, 0, 1, 0, -1};

bool Range (int x, int y) {
    if (x < 0 || x >= n || y < 0 || y >= m)
        return false;
    return true;
}

void change (int x, int y) {
    for (int i = 0; i < 5; i ++) {
        int xx = x + dx[i], yy = y + dy[i];
        if (Range (xx, yy))     a[xx][yy] ^= 1;
    }
    tmp[x][y] = 1;
}

void dfs () {
    int cnt = 0x3f3f3f3f;
    for (int _ = 0; _ <  1 << m; _ ++) {//第一行的情况有2^m种
        int step = 0;
        memset (tmp, 0, sizeof tmp); //方案置0
        memcpy (a, b, sizeof b); //backup, a=b

        for (int i = 0; i < m; i ++) {
            if (_ >> i & 1) { //保证字典序最小
                step ++;
                change (0, i);
            }
        }

        for (int i = 1; i < n; i ++)
            for (int j = 0; j < m; j ++) {
                if (a[i-1][j] == '1') { //根据上一行的情况来改变本行
                    step ++;
                    change (i, j);
                }
            }

        bool suc = true;
        for (int i = 0; i < m; i ++) {
            if (a[n-1][i] == '1') {
                suc = false;
                break;
            }
        }

        if (suc && step < cnt) {
            cnt  = step;
            memcpy (ans, tmp, sizeof tmp);
        }
    }

    if (cnt == 0x3f3f3f3f)  cout << "IMPOSSIBLE\n";
    else {
        for (int i = 0; i < n; i ++) {
            for (int j = 0; j < m; j ++)
                cout << ans[i][j] << ' ';
            cout << endl;
        }
    }
}

int main () {
    cin >> n >> m;
    for (int i = 0; i < n; i ++)
        for (int j = 0; j < m; j ++)
            cin >> b[i][j];

    dfs  ();
   
}
//dfs + 记录方案

5. 找倍数

bfs
按照题目要求,把所有可能一股脑填进去即可

#include <bits/stdc++.h>

using namespace std;
int n;
typedef pair<string, int> psi; //m  余数

void bfs () {
    queue <psi> q;
    q.push ({"1", 1});

    while (!q.empty ()) {
        auto t = q.front ();
        q.pop ();

        if (t.second == 0)  {
            cout << t.first << endl;
            return ;
        }

        q.push ({t.first + "1", (t.second * 10 + 1) % n});
        q.push ({t.first + "0", t.second * 10 % n});
    }
}

int main () {
    while (cin >> n, n) {
        bfs ();
    }
}

//找到n的非0倍数(只由01组成)
//所有可能一股脑填进去得了

6. 质数路径

有点暴力的思想,二重循环枚举每一种可能性

#include <bits/stdc++.h>

using namespace std;
int a, b;
const int N = 10000;
int d[N];
int dx[] = {1, 10, 100, 1000};

bool is_prime (int x) {
    for (int i = 2; i * i <= x; i ++)
        if (x % i == 0) {
            return false;
        }
    return true;
}

void bfs () {
    queue <int> q;
    memset (d, 0x3f, sizeof d);
    d[a] = 0;
    q.push ({a});

    while (!q.empty ()) {
        auto t = q.front ();
        q.pop();

        if (t == b) {
            cout << d[b] << endl;
            return ;
        }

        int num[4];
        num[0] = t % 10, num[3] = t / 1000;
        num[2] = t / 100 % 10, num[1] = t / 10 % 10;

        for (int i = 0; i < 4; i ++)
            for (int j = 0; j < 10; j ++) {
                if (i == 3 && j == 0)   continue; //不足四位
                if (j == num[i])    continue;
                int tmp = t + (j - num[i]) * dx[i];

                if (d[tmp] != 0x3f3f3f3f || !is_prime (tmp))    continue;
                d[tmp] = d[t] + 1;
                q.push (tmp);
            }

    }
}

void solve () {
    cin >> a >> b;
    if (a == b) {
        cout << "0\n";
        return ;
    }
    bfs ();
}

int main () {
    int t;
    cin >> t;
    while (t --) {
        solve ();
    }
}

7. 洗牌

模拟题
呜呜呜太难调了,讨厌模拟题

#include <bits/stdc++.h>

using namespace std;

string change (string a, string b) {
    string s;
    int n = a.size ();
    for (int i = 0; i < n; i ++)    s += b[i], s += a[i];
    return s;
}

void solve () {
    int n, cnt = 1;
    cin >> n;
    string s1, s2, s3;
    cin >> s1 >> s2 >> s3;

    set <string> mp;
    string t = change (s1, s2);
    //mp.insert (t);

    while (1) {
        
        if (mp.find (t) != mp.end ()) {
            cnt = -1;
            break;
        }
        else if (s3 == t)   break;
        else    mp.insert (t);
        t = change (t.substr (0, n), t.substr (n, n));
        cnt ++;
    }
    cout << cnt << endl;
}

int main () {
    int t;
    cin >> t;
    for (int i = 1; i <= t; i ++) {
        cout << i << ' ';
        solve ();
    }
}

//这题怕不是模拟吧
//拜托看清楚上下的顺序

8. 罐子

这道题目乍一看有些懵,但其实分析一下就会发现是“抽象路径”的bfs,即把操作当做不同的状态来看,然后正常做bfs即可。
记录路径我觉得比较新奇,就是用字符串来储存历史路径。
具体看代码吧,一看就懂的:

#include <bits/stdc++.h>

using namespace std;
const int N = 105; //最大容量
int A, B, C;
string idx[] = {"FILL(1)","FILL(2)","DROP(1)","DROP(2)","POUR(1,2)","POUR(2,1)"};
int d[N][N];

struct pot {
    int x, y;
    string op; //记录所有历史操作
};

void bfs () {
    memset (d, 0x3f, sizeof d);
    queue <pot> q;
    q.push({0,0,""});
    d[0][0]=0;

    while (!q.empty()) {
        auto t = q.front();
        q.pop();
        int a = t.x, b=t.y; //原容积

        if (a==C || b == C) {
            cout << d[a][b] <<endl;
            string ans = t.op;
            for (int i = 0; i < ans.size(); i ++) cout <<idx[ans[i]-'0'] << endl;
            return ;
        }

        //现容积
        int dx[] = {A, a, 0, a, max(0,a-B+b), min(A,a+b)};
        int dy[] = {b, B, b, 0, min(B, a+b), max(0,b-A+a)};

        for (int i = 0; i < 6; i ++) {
            int xx = dx[i], yy = dy[i];
            if (d[xx][yy] != 0x3f3f3f3f)    continue; //非最短
            d[xx][yy] = d[a][b] + 1;
            q.push ({xx, yy, t.op+to_string(i)});
        }
    }
    cout << "impossible";
}

int main () {
    cin >> A >> B >> C;
    bfs ();
}

//FILL(1): t1=A,t2=b;
//FILL(2): t1=a,t2=B;
//DROP(1): t1=0,t2=b; 
//DROP(2): t1=a,t2=0;
//pour(1,2):t1=max(0,a-B+b),t2=min(B,a+b);
//pour(2,1):t1=min(A,a+b),t2=max(0,b-A+a);

//抽象路径
//存六种状态

9. 点火游戏

欲哭无泪。。想假了,想复杂了。。。
直接暴力枚举就好
如果想看我的错误思路的话(肯定没有人),可以划到代码最后面,都写在注释里面了

#include <bits/stdc++.h>

using namespace std;
typedef pair<int, int> pii;

const int N = 15;
int n, m, tot;
int d[N][N];
char a[N][N];
int dx[] = {0, 1, 0, -1}, dy[] = {1, 0, -1, 0};

bool Range (int x, int y) {
    if (x <= 0 || x > n || y <= 0 || y > m) return false;
    return true;
}

int bfs (pii x, pii y) {
    memset (d, 0x3f, sizeof d);
    int ans = 0, cnt = 1;
    d[x.first][x.second] = d[y.first][y.second] = 0;

    queue<pii> q;
    q.push (x);
    if (x != y) q.push (y), cnt ++;

    while (!q.empty ()) {
        auto t = q.front();
        q.pop();

        for (int i = 0; i < 4; i ++) {
            int xx = t.first + dx[i], yy = t.second + dy[i];
            if (!Range (xx, yy) || a[xx][yy] != '#' || d[xx][yy] != 0x3f3f3f3f)    continue;
            d[xx][yy] = d[t.first][t.second] + 1;
            ans = max (ans, d[xx][yy]);
            q.push ({xx, yy});
            cnt ++;
        }
    }
    if (cnt == tot)   return ans;
    return 1e9;
}

void solve () {
    vector <pii> v;
    tot = 0; //草地个数
    cin >> n >> m;
    for (int i = 1; i <= n; i ++)
        for (int j = 1; j <= m; j ++) {
            cin >> a[i][j];
            if (a[i][j] == '#') 
                v.push_back ({i, j}), tot ++;
        }

    int ans = 1e9;
    for (auto i : v)
        for (auto j : v)
            ans = min (bfs (i,j), ans);

    if (ans == 1e9) ans = -1;
    cout << ans << endl;

}

int main () {
    int t;
    cin >> t;
    for (int i = 0; i <t; i ++) {
        cout << "Case " << i+1 << ": ";
        solve ();
    }
}
//对于每一个连通块,一定是从最中间开始燃烧为最优
//因此,画图发现,数量固定则时间固定

//选择两个#,要多久能遍历所有的#
//.视为障碍物
//先找连通块,统计个数n,同时统计每个的size

//n==0||n>2,则impossible
//n=2,输出二者当中较大的那个size/2  //分成两段所以除2
//n=1,输出size/3

//我知道我的问题在哪里了。。
//当出现:
// #..####
// #.#.###
// ##.#.##
//这种情况的时候,看似是两个连通块,但是不能分开处理。。因为中间那个燃烧之后会连上
//所以。。。直接暴力枚举两个点www

//好吧。。看数据范围就知道要暴力了,n才15

10. 起火迷宫

先预处理出每一个被火种覆盖到所需要的时间
然后正常的做bfs(记得时刻更新状态)

#include <bits/stdc++.h>

using namespace std;
typedef pair<int, int>pii;
const int N = 1005;
char a[N][N];
int dx[]= {1, 0, -1, 0}, dy[] = {0, 1, 0, -1};
int n, m, sx, sy, ans;
queue <pii> fire;
int f[N][N], d[N][N]; //火烧到的时间,人走到的时间

bool Range (int x, int y) {
    if (x > 0 && x <= n && y > 0 && y <= m)
        return true;
    return false;
}

void bfs1 () {
    //预处理出每一个被火种覆盖到所需时间
    while (!fire.empty ()) {
        auto t = fire.front ();
        fire.pop();

        int x = t.first, y = t.second;
        for (int i = 0; i < 4; i ++) {
            int xx = x + dx[i], yy = y + dy[i];
            if (a[xx][yy] == '#' || !Range (xx, yy) || f[xx][yy] != 0x3f3f3f3f)    continue;
            f[xx][yy] = f[x][y] + 1;
            fire.push ({xx, yy});
        }
    }
}

int bfs2 () {
    if (sx == n || sy == m || sx == 1 || sy == 1)   return 1; //最开始就能走到的特判一下
    queue <pii> q;
    q.push ({sx, sy});
    d[sx][sy] = 0;

    while (!q.empty ()) {
        auto t = q.front ();
        q.pop();
        for (int i = 0; i < 4; i ++) {
            int xx = t.first + dx[i], yy = t.second + dy[i];
            if (!Range (xx, yy) || a[xx][yy] == '#')    continue; //越界或走不到
            if (d[t.first][t.second] + 1 >= f[xx][yy] || d[xx][yy] != 0x3f3f3f3f)    continue; //大火已经烧到了或非最短路

            d[xx][yy] = d[t.first][t.second] + 1;
            if (xx == n || yy == m || xx == 1 || yy == 1)   return d[xx][yy] + 1;
            q.push ({xx, yy});
        }
    }
    return -1;
}

void solve () {
    memset (d, 0x3f, sizeof d);
    memset (f, 0x3f, sizeof f);
    while (!fire.empty ())  fire.pop();

    cin >> n >> m;
    for (int i = 1; i <= n; i ++)
        for (int j = 1; j <= m; j ++) {
            cin >> a[i][j];
            if (a[i][j] == 'J')
                sx = i, sy = j;
            if (a[i][j] == 'F')
                fire.push ({i, j}), f[i][j] = 0;
        }
    bfs1 ();

    int ans = bfs2 ();
    if (ans == -1)    cout << "IMPOSSIBLE\n";
    else    cout << ans << endl;

}

int main () {
    int t;
    cin >> t;
    while (t --) {
        solve ();
    }
}

//起火了就填上#
//把F存起来,挨个扩散
//TLE 了。。允悲

//先求出所有格子被火覆盖的最短时间(多源bfs, 有多个火种)

11.迷宫问题

bfs + 路径记录(倒着来)

#include <bits/stdc++.h>

using namespace std;
typedef pair<int, int> pii;
int n;
const int N = 1005;
int a[N][N], d[N][N];
int dx[] = {0, 1, 0, -1}, dy[] = {1, 0, -1, 0};
pii ans[N][N];

bool Range (int x, int y) {
    if (x >= 0 && x < n && y >= 0 && y < n) return true;
    return false;
}

void bfs () {
    queue <pii> q;
    q.push ({0, 0});
    d[0][0] = 0;

    while (!q.empty ()) {
        auto t = q.front ();
        q.pop();

        for (int i = 0; i < 4; i ++) {
            int xx = t.first + dx[i], yy = t.second + dy[i];
            if (d[xx][yy] != 0x3f3f3f3f || a[xx][yy] == 1 || !Range (xx, yy))  continue;
            q.push ({xx, yy});
            d[xx][yy] = d[t.first][t.second] + 1;
            ans[xx][yy] = {t.first, t.second}; //更新路径
            if (xx == n - 1 && yy == n - 1) return ;
        }
    }
}

int main () {
    memset (d, 0x3f, sizeof d);
    cin >> n;
    for (int i = 0; i < n; i ++)
        for (int j = 0; j < n; j ++)
            cin >> a[i][j];

    bfs ();

    //关键:输出路径(易错)
    cout << "0 0\n";
    pii t = ans[n-1][n-1];

    vector <pii> q;
    while (t.first != 0 || t.second != 0) { //注意是或
        q.push_back (t);
        //cout << t.first << ' ' << t.second << endl;
        t = ans[t.first][t.second];
    }
    reverse (q.begin (), q.end ());
    for (auto i : q)    cout << i.first << ' ' << i.second << endl;
    cout << n-1 << ' ' << n-1 << endl;
}

//最短路 + 记录路径

12. 石油储备

八连通,找连通块个数,bfs/dfs都可以

#include <bits/stdc++.h>

using namespace std;
typedef pair<int, int> pii;
int n, m;
const int N = 105;
char a[N][N];
int dx[] = {-1, -1, -1,  0, 0,  1, 1, 1};
int dy[] = {-1,  0,  1, -1, 1, -1, 0, 1};

bool Range (int x, int y) {
    if (x >= 0 && x < n && y >= 0 && y < m)
        return true;
    return false;
}

void bfs (int x, int y) {
    queue <pii> q;
    q.push ({x, y});
    while (!q.empty ()) {
        auto t = q.front ();
        q.pop();
        for (int i = 0; i < 8; i ++) {
            int xx = t.first + dx[i], yy = t.second + dy[i];
            if (a[xx][yy] == '@' && Range (xx, yy)) {
                q.push ({xx, yy});
                a[xx][yy] = '$';
            }
        }
    }

}

int main () {
    while (cin >> n >> m, n || m) {
        int cnt = 0;
        for (int i = 0; i < n; i ++)
            cin >> a[i];

        for (int i = 0; i < n; i ++)
            for (int j = 0; j < m; j ++)
                if (a[i][j] == '@')
                    bfs (i, j), cnt ++;

        cout << cnt << endl;
    }

}
//八连通

13. 非常可乐

这题简直和AcWing 4222. 罐子 一模一样

3种杯子,6种操作:

1->2          1->3            2->3            
max(0,a+b-n)  max(0,a+c-m)    a               
min(a+b,n)    b               max(0,b+c-m)    
c             min(a+c,m)      min(b+c,m)      

2->1          3->1            3->2
min(s,a+b)    min(s,a+c)      a
max(0,a+b-s)  b               min(n,b+c)
c             max(0,a+c-s)    max(b+c-n,0)
#include <bits/stdc++.h>

using namespace std;
const int N = 105;
int s, n, m;
int d[N][N][N];

struct cola {
    int a, b, c;
};

bool check (int a, int b, int c) {
    if (a == s/2 && b == s/2 && c == 0) return true;
    if (a == s/2 && c == s/2 && b == 0) return true;
    if (b == s/2 && c == s/2 && a == 0) return true;
    return false;
}

void bfs () {
    memset (d, 0x3f, sizeof d);
    queue <cola> q;
    q.push ({s, 0, 0});
    d[s][0][0] = 0;

    while (!q.empty ()) {
        auto t = q.front ();
        q.pop ();
        int a = t.a, b = t.b, c = t.c;

        int dx[] = {max(0,a+b-n), max(0,a+c-m), a, min(s,a+b), min(s,a+c), a};
        int dy[] = {min(a+b,n), b, max(0,b+c-m), max(0,a+b-s), b, min(n,b+c)};
        int dz[] = {c, min(a+c,m), min(b+c,m), c, max(0,a+c-s), max(b+c-n,0)};

        for (int i = 0; i < 6; i ++) {
            int xx = dx[i], yy = dy[i], zz = dz[i];
            if (d[xx][yy][zz] != 0x3f3f3f3f)    continue;
            d[xx][yy][zz] = d[a][b][c] + 1;
            q.push ({xx, yy, zz});
            if (check (xx, yy, zz)) {
                cout << d[xx][yy][zz] << endl;
                return ;
            }
        }
    }
    cout << "NO\n";
}

int main () {
    while (cin >> s >> n >> m, n || m || s) {
        if (s & 1) {
            cout << "NO\n";
            continue;
        }
        bfs ();
    }

}

//3种杯子,6种操作
//1->2          1->3            2->3            
//max(0,a+b-n)  max(0,a+c-m)    a               
//min(a+b,n)    b               max(0,b+c-m)    
//c             min(a+c,m)      min(b+c,m)      

//2->1          3->1            3->2
//min(s,a+b)    min(s,a+c)      a
//max(0,a+b-s)  b               min(n,b+c)
//c             max(0,a+c-s)    max(b+c-n,0)

14. 找路

属于是有些笨了。。
一开始写的是对于每个餐厅做两次bfs....然后TLE了(因为要做很多次)
其实只用做两次,一次Y,一次M,然后预处理两个距离再求和即可

#include <bits/stdc++.h>

using namespace std;
const int N = 205;
typedef pair<int, int>pii;
int n, m, sx, sy, fx, fy;
char a[N][N];
int d1[N][N], d2[N][N];

int dx[] = {0, 1, 0, -1}, dy[] = {1,0, -1, 0};
vector <pii> v; //canteen

bool Range (int x, int y) {
    if (x <= 0 || x > n || y <= 0 || y > m) return false;
    return true;
}

void bfs1() {
    memset (d1, 0x3f, sizeof d1);
    queue <pii> q;
    q.push ({sx, sy});
    d1[sx][sy] = 0;

    //Y
    while (!q.empty ()) {
        auto t = q.front ();
        q.pop();

        for (int i = 0; i < 4; i ++) {
            int xx = t.first + dx[i], yy = t.second + dy[i];
            if (!Range (xx, yy) || d1[xx][yy] != 0x3f3f3f3f) continue;
            if (a[xx][yy] == '#')   continue;
            d1[xx][yy] = d1[t.first][t.second] + 1;
            q.push ({xx, yy});
        }
    }
}

void bfs2() {
    memset (d2, 0x3f, sizeof d2);
    queue <pii> q;
    q.push ({fx, fy});
    d2[fx][fy] = 0;

    //M
    while (!q.empty ()) {
        auto t = q.front ();
        q.pop();

        for (int i = 0; i < 4; i ++) {
            int xx = t.first + dx[i], yy = t.second + dy[i];
            if (!Range (xx, yy) || d2[xx][yy] != 0x3f3f3f3f) continue;
            if (a[xx][yy] == '#')   continue;
            d2[xx][yy] = d2[t.first][t.second] + 1;
            q.push ({xx, yy});
        }
    }
}

int main () {
    while (cin >> n >> m) {
        v.clear();
        for (int i = 1; i <= n; i ++)
            for (int j = 1; j <= m; j ++) {
                cin >> a[i][j];
                if (a[i][j] == 'Y') sx = i, sy = j;
                else if (a[i][j] == 'M')    fx = i, fy = j;
                else if (a[i][j] == '@')    v.push_back ({i, j});
            }

        bfs1 ();
        bfs2 ();

        int minn = 1e9;
        for (auto i : v) {
            int x = i.first, y = i.second;
            minn = min (minn, d1[x][y] + d2[x][y]);
        }
        cout << 11ll * minn << endl;
    }

}

//对于每一个餐厅都做两次bfs,求和;记录最小值
posted @ 2022-07-02 17:25  Sakana~  阅读(36)  评论(1编辑  收藏  举报