洛谷1514 引水入城

原题链接

对于第一个问题,显然\(DFS\)\(BFS\)一遍看看最后一排是不是全部被搜到即可。
对于第二个问题,考虑贪心,求出第一排每个格子最大能够覆盖多少最后一排的格子,即求左端右端(显然覆盖的格子都是连续的,若不为连续,则那个断开的格子定无法到达)。
可以使用\(DP\)来求出,设\(L[x][y],R[x][y]\)分别表示对于格子\((x,y)\),从它出发能够覆盖最后一排的格子的最左端和最右端,显然\(L[x][y] = \min \{ L[x ^ \prime][y ^ \prime] \},R[x][y] = \max \{ R[x ^ \prime][y ^ \prime] \}\)\((x ^ \prime, y ^ \prime)\)是格子\((x, y)\)能够到达的格子。
这里我是使用记忆化搜索来求的,这样可以在用\(DFS\)求解第一个问题的时候同时求出。
因为据说这题若构造特殊数据能把\(DFS\)弄爆栈,所以我使用了手工栈,另外附上非手工栈版本。

#include<cstdio>
#include<cstring>
using namespace std;
const int N = 510;
struct dd{
    int i, x, y, xx, yy;
};
dd sta[N * N];
int a[N][N], L[N][N], R[N][N], mo_x[4] = {0, 0, 1, -1}, mo_y[4] = {1, -1, 0, 0}, n, m, tp;
bool v[N][N];
inline int re()
{
    int x = 0;
    char c = getchar();
    bool p = 0;
    for (; c < '0' || c > '9'; c = getchar())
        p |= c == '-';
    for (; c >= '0' && c <= '9'; c = getchar())
        x = x * 10 + c - '0';
    return p ? -x : x;
}
inline int minn(int x, int y)
{
    return x < y ? x : y;
}
inline int maxn(int x, int y)
{
    return x > y ? x : y;
}
/*非手工栈版本
void dfs(int x, int y)
{
    v[x][y] = 1;
    int i, xx, yy;
    for (i = 0; i < 4; i++)
    {
        xx = x + mo_x[i];
        yy = y + mo_y[i];
        if (a[xx][yy] < a[x][y] && xx > 0 && xx <= n && yy > 0 && yy <= m)
        {
            if (!v[xx][yy])
                dfs(xx, yy);
            L[x][y] = minn(L[x][y], L[xx][yy]);
            R[x][y] = maxn(R[x][y], R[xx][yy]);
        }
    }
}
*/
void dfs(int xo, int yo)
{
    sta[tp = 1].x = xo;
    sta[1].y = yo;
start:
    v[sta[tp].x][sta[tp].y] = 1;
    for (sta[tp].i = 0; sta[tp].i < 4; sta[tp].i++)
    {
        sta[tp].xx = sta[tp].x + mo_x[sta[tp].i];
        sta[tp].yy = sta[tp].y + mo_y[sta[tp].i];
        if (a[sta[tp].xx][sta[tp].yy] < a[sta[tp].x][sta[tp].y] && sta[tp].xx > 0 && sta[tp].xx <= n && sta[tp].yy > 0 && sta[tp].yy <= m)
        {
            if (!v[sta[tp].xx][sta[tp].yy])
            {
                sta[tp + 1].x = sta[tp].xx;
                sta[tp + 1].y = sta[tp].yy;
                tp++;
                goto start;
            }
        end:
            L[sta[tp].x][sta[tp].y] = minn(L[sta[tp].x][sta[tp].y], L[sta[tp].xx][sta[tp].yy]);
            R[sta[tp].x][sta[tp].y] = maxn(R[sta[tp].x][sta[tp].y], R[sta[tp].xx][sta[tp].yy]);
        }
    }
    if (--tp)
        goto end;
}
int main()
{
    int i, j, s = 0, l = 1, r;
    bool p = 0;
    n = re();
    m = re();
    memset(L, 60, sizeof(L));
    for (i = 1; i <= m; i++)
        L[n][i] = R[n][i] = i;
    for (i = 1; i <= n; i++)
        for (j = 1; j <= m; j++)
            a[i][j] = re();
    for (i = 1; i <= m; i++)
        if (!v[1][i])
            dfs(1, i);
    for (i = 1; i <= m; i++)
        if (!v[n][i])
        {
            p = 1;
            s++;
        }
    if (p)
    {
        printf("0\n%d", s);
        return 0;
    }
    for (s = r = 0; l <= m; r = 0, s++)
    {
        for (i = 1; i <= m; i++)
            if (L[1][i] <= l)
                r = maxn(r, R[1][i]);
        l = r + 1;
    }
    printf("1\n%d", s);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Iowa-Battleship/p/9812754.html