Rising Tides

Last May, the UCF Programming Team attended the ACM ICPC World Finals in Phuket, Thailand. Besides the exciting programming contest, Thailand had some great sights to see!

The Phang Nga Bay in Thailand is home to hundreds of islands, some of which (e.g., James Bond Island) are famous from movie scenes. Others have lagoons inside that can only be reached by canoeing through caves on the water. Some caves have ceilings so low that canoers must lean over to make it through.

MAVK8IYGLRDGKKQG4GDK%0I.png

Besides navigating the tricky passages of the caves, canoers must be aware of the tides. Some caves can only be traversed in low tide. As the tides change, the sea level rises or falls while the explorers are paddling, and they must be careful to choose the correct path through the cave to avoid getting trapped. Of course, if they can make it through, they also want to minimize the amount of energy they spend leaning over in the canoe, i.e., they prefer higher ceiling heights when going through the caves.

In this problem, we assume that canoers start their journey at low tide and the sea level rises by one millimeter each second. Each cave is described by a two-dimensional grid (table) of numbers, where the j.png number in the i.png row indicates the initial height in millimeters of the cave ceiling at position (݅,݆) on the surface of the water. Because of the sea level change, the ceiling height (the distance from the sea level to the ceiling) at each cell decreases over time.

The cave can be traversed by starting at the first column of the first row (i.e., northwest corner) and ending at the last column of the last row (i.e., southeast corner). The canoe only moves in one of four directions in the two-dimensional grid (north, south, east, or west), one move at a time. Each second, the canoe moves to an adjacent cell and the sea level increases by one millimeter, and the height of the cell above sea level must be greater than zero when the canoe enters it. The canoe’s move and sea level change happen simultaneously, so the ceiling height may become zero just as the canoe is leaving. You may assume that the height of the cave above the canoe’s initial position is greater than zero.

The Problem:

Given the description of a cave, you must find the path with the highest minimum ceiling height, or determine that it is impossible to traverse. Note that the number of cells the path goes through is not important; rather the heights of the cells are important; in particular, you are to find the path with the largest minimum ceiling height.

The Input:

The first line of input contains a single positive integer, n, indicating the number of caves to process. This is followed by n cave descriptions. Each cave description begins with a line containing two integers, r and c (1 ≤ r ≤ 500 and 1 ≤ c ≤ 500), denoting the number of rows and columns, respectively. The next r lines each contain c space-separated integers, with the ith number on the jth line representing the height aij.png(0 ≤aij.png≤ 1000,000,000;a11> 0) in millimeters of the cave ceiling above the initial sea level.

The Output:

For each cave, output a line with a single integer k denoting the largest minimum ceiling height, in millimeters, of a path through the cave, or the word impossible if the cave can’t be traversed.

样例输入
2 
4 5 
9 5 4 0 0 
9 4 8 9 12 
9 6 8 7 12 
0 0 9 8 12 
3 1 
10 
1 
10
样例输出
3 

错到怀疑人生的一道题
在这里插入图片描述
刚看到时觉得是一道宽搜水题,然后写了一个宽搜一交就MLE了。
改了好几次发现是队列超的,然后就通过h判掉一些res相等的情况,然后就TLE了。
之后觉得可以用基于贪心的Dijkstra快速找到答案,然后又WA了
WA掉的Dijkstra

#include <bits/stdc++.h>

using namespace std;

const int N = 505;
struct P {
    int x, y, h, res;

};

inline bool operator<(const P &a, const P &b) {
    return a.res < b.res || (a.res == b.res && a.h > b.h);
}

struct S {
    int res, h;
};
int n, m, a[N][N], T;
bool v[N][N];
S sta[N][N];
int dx[4] = {1, 0, -1, 0};
int dy[4] = {0, 1, 0, -1};

inline bool check(int x, int y) {
    return x <= n && x >= 1 && y <= m && y >= 1;
}

void out() {
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            if (sta[i][j].res >= 10)
                printf("%d ", sta[i][j].res);
            else
                printf("%d  ", sta[i][j].res);
        }
        printf("     ");
        for (int j = 1; j <= m; j++) {
            if (sta[i][j].h >= 10)
                printf("%d ", sta[i][j].h);
            else
                printf("%d  ", sta[i][j].h);
        }
        puts("");
    }
    puts("");
}

inline bool dijkstra() {
    priority_queue<P> q;
    sta[1][1] = {a[1][1], 0};
    q.push({1, 1, 0, a[1][1]});
    while (!q.empty()) {
        P t = q.top();
        q.pop();
        if (v[t.x][t.y])continue;
        if (t.x == n && t.y == m)return true;
        v[t.x][t.y] = true;
        for (int i = 0; i < 4; i++) {
            int nx = t.x + dx[i], ny = t.y + dy[i];
            if (!check(nx, ny) || t.h + 1 >= a[nx][ny])continue;
            int nres = min(t.res, a[nx][ny] - t.h - 1);
            if (nres > sta[nx][ny].res || (nres == sta[nx][ny].res && t.h + 1 < sta[nx][ny].h)) {
                sta[nx][ny] = {nres, t.h + 1};
                //out();
                P nt = {nx, ny, t.h + 1, nres};
                q.push(nt);
            }
        }
    }
    return false;
}

int main() {
    cin >> T;
    while (T--) {
        scanf("%d%d", &n, &m);
        memset(a, 0, sizeof(a));
        memset(v, false, sizeof(v));
        memset(sta, 0, sizeof(sta));
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= m; j++)
                scanf("%d", &a[i][j]);
        dijkstra() ? printf("%d\n", sta[n][m]) : puts("impossible");
    }
    return 0;
}

用之前TLE的代码对拍了好久,找到了一个hack数据

1
10 10
20 44 30 20 11 58 35 42 16 51 
56 25 35 24 52 10 30 22 10 15 
20 42 10 20 40 35 54 26 46 14 
44 12 48 10 20 30 10 12 54 36 
12 15 58 35 22 20 34 18 17 35 
50 42 40 41 27 20 20 54 50 58 
10 34 15 10 22 40 28 26 41 10 
40 22 10 54 20 10 15 56 42 42 
37 19 22 14 42 45 27 45 48 40 
46 16 48 43 26 41 45 26 10 26 

然后通过输出计算过程找到了问题
这是朴素bfs的某过程
左边是当前最大的最小值res,右边是水面高度

20 20 20 17 7  20 20 20 7  7       0  1  2  3  4  11 10 11 8  9
20 20 20 20 20 4  20 12 1  5       1  2  3  4  5  6  9  10 9  10
18 20 6  15 20 20 20 17 17 3       2  3  4  5  6  7  8  9  10 11
18 8  13 4  13 20 1  2  17 17      3  4  11 6  7  8  9  10 11 12
8  8  13 13 13 11 11 7  5  17      4  5  10 9  8  9  10 11 12 13
13 13 13 13 13 10 9  17 17 17      13 12 11 10 9  10 11 16 15 14
4  13 7  1  12 12 12 12 17 0       6  13 8  9  10 11 12 13 16 0
8  8  1  9  9  0  2  12 17 12      9  8  9  12 11 0  13 14 17 16
8  8  8  3  9  11 11 12 12 12      10 9  10 11 12 17 16 15 16 17
8  6  9  9  9  9  11 10 0  8       11 10 15 14 13 14 17 16 0  18

这是Dijkstra的某过程

20 20 20 17 0  0  0  0  0  0       0  1  2  3  0  0  0  0  0  0
20 20 20 20 20 4  0  0  0  0       1  2  3  4  5  6  0  0  0  0
18 20 6  15 20 0  0  0  0  0       2  3  4  5  6  0  0  0  0  0
0  8  0  0  0  0  0  0  0  0       0  4  0  0  0  0  0  0  0  0
0  0  0  0  0  0  0  0  0  0       0  0  0  0  0  0  0  0  0  0
0  0  0  0  0  0  0  0  0  0       0  0  0  0  0  0  0  0  0  0
0  0  0  0  0  0  0  0  0  0       0  0  0  0  0  0  0  0  0  0
0  0  0  0  0  0  0  0  0  0       0  0  0  0  0  0  0  0  0  0
0  0  0  0  0  0  0  0  0  0       0  0  0  0  0  0  0  0  0  0
0  0  0  0  0  0  0  0  0  0       0  0  0  0  0  0  0  0  0  0

20 20 20 17 5  0  0  0  0  0       0  1  2  3  6  0  0  0  0  0
20 20 20 20 20 4  0  0  0  0       1  2  3  4  5  6  0  0  0  0
18 20 6  15 20 0  0  0  0  0       2  3  4  5  6  0  0  0  0  0
0  8  0  0  0  0  0  0  0  0       0  4  0  0  0  0  0  0  0  0
0  0  0  0  0  0  0  0  0  0       0  0  0  0  0  0  0  0  0  0
0  0  0  0  0  0  0  0  0  0       0  0  0  0  0  0  0  0  0  0
0  0  0  0  0  0  0  0  0  0       0  0  0  0  0  0  0  0  0  0
0  0  0  0  0  0  0  0  0  0       0  0  0  0  0  0  0  0  0  0
0  0  0  0  0  0  0  0  0  0       0  0  0  0  0  0  0  0  0  0
0  0  0  0  0  0  0  0  0  0       0  0  0  0  0  0  0  0  0  0

第1行的第5列最优res是7,但是基于Dijkstra的程序得出的是5.根本原因是到达(1,5)的船来自(2,5)而不是(1,4).而来自(2,5)的原因是(2,5)的res是20,大于(1,4)的17.如果终点是(1,5)的话那么就会得到一个错误答案.
总结来说Dijkstra不适用于这道题的情形。因为正常的Dijkstra选择扩展边根本上只取决于一类参数,而这道题既取决于h又取决于res,取当前res最大的边中h最小的边扩展,但是这条边的h还是特别大,之后会更新到一个特别小的res,而另一条边虽然当前res较小,但是h特别小,之后res减少的很小,显然后者更优。

其实通过二分res即可求出

#include<bits/stdc++.h>

using namespace std;
const int N = 505;
struct P {
    int x, y, h;
};
int n, m, a[N][N], T;
bool v[N][N];
int dx[4] = {1, 0, -1, 0};
int dy[4] = {0, 1, 0, -1};

inline bool check(int x, int y) {
    return x <= n && x >= 1 && y <= m && y >= 1;
}

bool dfs(int res) {
    memset(v, false, sizeof(v));
    queue<P> q;
    q.push({1, 1, 0});
    v[1][1] = true;
    while (!q.empty()) {
        P t = q.front();
        q.pop();
        if (t.x == n && t.y == m)return true;
        for (int i = 0; i < 4; i++) {
            int nx = t.x + dx[i], ny = t.y + dy[i];
            if (v[nx][ny] || !check(nx, ny) || t.h + 1 >= a[nx][ny] - res)continue;
            if (nx == n && ny == m)return true;
            v[nx][ny] = true;
            q.push({nx, ny, t.h + 1});
        }
    }
    return false;
}

int main() {
    cin >> T;
    while (T--) {
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= m; j++)
                scanf("%d", &a[i][j]);
        int l = -1, r = a[1][1] - 1;//l=-1下界往下挖1才能通过,即不能通过,
        while (l < r) {             //r=a[1][1]-1上界最大可以在这么高的水面通过
            int mid = (l + r + 1) >> 1;
            dfs(mid) ? (l = mid) : (r = mid - 1);
        }
        l + 1 ? printf("%d\n", l + 1) : puts("impossible");//因为l是能通过船的前提下初始水面的最大高度,
    }                                                      //说明该情况下最低高度为1,因此结果为l+1
    return 0;
}
发布了360 篇原创文章 · 获赞 28 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_45323960/article/details/105167113