补题记录G. To Go Or Not To Go?

补题记录:G. To Go Or Not To Go?

题意:给你一个二维的矩阵,每个点都有一个点权,A要从左上角(1,1)走到右下角(n,m),有如下规则。
1、如果是-1,说明不通,走不了
2、如果是0,说明可以通行
3、如果大于0,说明这是一个传送门,你可以在任意两个传送门之间任意传送,如果你从(i, j)传送到(x, y)那么花费就是\(a_{i, j} + a_{x, y}\)
你可以从任意一个格子走到相邻的合法格子,花费是w,问最后的最小花费是多少。
方法:最短路/BFS
主要还是思维的难度,代码并不难写。首先我们要知道,假如没有传送门就是一道简单的BFS题目。那么加上了这个传送门之后应该如何处理呢?
首先我们想,假如有传送门,我们应该用多少个传送门?
答案:1对就够了
其实很好理解,假如我们要从A传送到B,然后从C传送到D,我们不如直接从A传送到D。所以我们至多只需要一对传送门即可。
那么我们可以预处理出所有传送门到终点的距离,找到最小的那个就是最终我们要传送到的传送门,我们既为best_ed。然后再从起点枚举各个传送门传送到best_ed的距离,取最小值即可。
具体看代码,最后提醒下开long long

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL,LL> PLL;
const int INF = 0x3f3f3f3f, N = 2010;
inline int lc(int u) {return u << 1;}
inline int rc(int u) {return u << 1 | 1;}
inline int lowbit(int x) {return x & (-x);}
LL a[N][N];
int n, m, w;
int dx[4] = {1, 0, -1, 0}, dy[4] = {0, 1, 0, -1};
void bfs(int st, int ed, vector<vector<LL>> &d) {
    queue<PII> q;
    d[st][ed] = 0;
    q.push({st, ed});
    while (!q.empty()) {
        auto t = q.front();
        q.pop();
        for (int i = 0; i < 4; i ++ ) {
            int x = t.first + dx[i], y = t.second + dy[i];
            if (x < 1 || x > n || y < 1 || y > m || d[x][y] != -1 || a[x][y] == -1) continue;
            d[x][y] = d[t.first][t.second] + 1;
            q.push({x, y});
        }
    }
}
inline void solve() {
    cin >> n >> m >> w;
    for (int i = 1; i <= n; i ++ ) {
        for (int j = 1; j <= m; j ++ ) cin >> a[i][j];
    }
    vector<vector<LL>> d1(n + 1, vector<LL> (m + 1, -1));
    vector<vector<LL>> d2(n + 1, vector<LL> (m + 1, -1));
    bfs(1, 1, d1);
    bfs(n, m, d2);
    LL best_ed = LLONG_MAX;
    for (int i = 1; i <= n; i ++ ) {
        for (int j = 1; j <= m; j ++ ) {
            if (d2[i][j] != -1 && a[i][j] >= 1) {
                best_ed = min(best_ed, d2[i][j] * w * 1ll + a[i][j]);
            }
        }
    }
    LL res = w * 1ll * d1[n][m];
    if (d1[n][m] == -1) res = LLONG_MAX;
    for (int i = 1; i <= n; i ++ ) {
        for (int j = 1; j <= m; j ++ ) {
            if (d1[i][j] != -1 && a[i][j] >= 1 && best_ed != LLONG_MAX) {
                res = min(res, w * 1ll * d1[i][j] + a[i][j] + best_ed);
            }
        }
    }
    if (res == LLONG_MAX) cout << -1 << endl;
    else cout << res << endl;
}
int main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
//    int t; cin >> t;
//    while (t -- )
        solve();
    return 0;
}
posted @ 2021-05-07 16:53  Time_Limit_Exceeded  阅读(102)  评论(0编辑  收藏  举报