题意
给定一个矩形,第一排可以出水,水从高处往低处流,问是否能让最后一排全部接到水,如果不能输出有多少地方不能有水,如果能输出第一排最少多少个孔出水即可。
分析
其实可以归类于经典的迷宫问题,多了一个移动条件是海拔需要更高,难点是如何输出最少的出水孔。这里需要得到一个结论就是如果有解即最后一排所有方格都可达,每个孔出水后落到最后一排一定是个连续的区间。这样我们只需要记忆化一下第一排每个格子可以到达的最大左右区间,然后问题就变成了最少区间覆盖问题。
#include<bits/stdc++.h>
using namespace std;
const int N = 505;
int n, m;
int h[N][N],st[N][N],l[N][N],r[N][N];
int dx[] = { 0,1,-1,0 }, dy[] = { 1,0,0,-1 };
void dfs(int x, int y)
{
st[x][y] = 1;
for (int i = 0; i < 4; i++)
{
int tx = x + dx[i], ty = y + dy[i];
if (tx<1 || tx>n || ty<1 || ty>m||h[x][y]<=h[tx][ty])continue;
if(!st[tx][ty])dfs(tx, ty);
l[x][y] = min(l[x][y], l[tx][ty]);//递归到第一排去
r[x][y] = max(r[x][y], r[tx][ty]);
}
}
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)cin >> h[i][j];
memset(l, 0x3f, sizeof(l));
for (int i = 1; i <= m; i++)l[n][i] = i, r[n][i] = i;
for (int i = 1; i <= m; i++)
{
if (!st[1][i])dfs(1, i);
}
int cnt = 0,flag=0;
for (int i = 1; i <= m; i++)
if (!st[n][i])flag = 1, cnt++;
if (flag)
cout << 0 << endl << cnt << endl;
else
{
int lf = 1;
while (lf <= m)//最小区间覆盖
{
int mxr = 0;
for (int i = 1; i <= m; i++)
if (l[1][i] <= lf)mxr = max(mxr, r[1][i]);
cnt++;
lf = mxr + 1;
}
cout << 1 << endl;
cout << cnt << endl;
}
}