实际上看了下数据,第6个点只有一行,出现问题的原因是在floodfill时候出现了bug。就是dfs那里。
void dfs (int x, int y) {//错误扩展方式
for(int i = 0; i < 4; ++i) {
int nx = x + dx[i], ny = y + dy[i];
if(nx < 1 || nx > n || ny < 1 || ny > m || vis[nx][ny] == state) continue;
if(w[nx][ny] < w[x][y]) vis[x][y] = state, dfs(nx, ny);
}
}
对于floodfill大家很熟悉,但是有时候不小心就会写错。 对于函数入口一般分两种:第一种是先判断当前点出界情况和是否是访问过的区域再做访问标记再直接扩展第二种是先做访问标记再判断不出界情况和未访问的区域进行扩展,两个写法千万不可混用。
上面的错误写法是先判断不出界情况和排除访问过的区域,再进行扩展和访问标记。这样就会可能忽略掉当前点就是可访问点的情况。所以就会造成只有一行的情况下当前点无法扩展,也不会被标记。
对于本题的情况,正确处理方式应该是第一个点保证可行点的情况下,直接用第二种写法,在开头做访问标记。
完整正确的代码如下:
#include <bits/stdc++.h>
using namespace std;
const int Maxn = 500 + 2;
int n, m;
int w[Maxn][Maxn], vis[Maxn][Maxn];
int st[Maxn], ed[Maxn];
int con = 0, state;
int dx[] = {0, -1, 0, 1};
int dy[] = {-1, 0, 1, 0};
void dfs (int x, int y) {
vis[x][y] = state;
for(int i = 0; i < 4; ++i) {
int nx = x + dx[i], ny = y + dy[i];
if(nx < 1 || nx > n || ny < 1 || ny > m || vis[nx][ny] == state) continue;
if(w[nx][ny] < w[x][y]) dfs(nx, ny);
}
}
int main() {
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j)
scanf("%d", &w[i][j]);
for(int i = 1; i <= m; ++i) {
state = i, dfs(1,i);
st[i] = ed[i] = 0;
for(int x = 1; x <= m; ++x)
if(vis[n][x] == state) {st[i] = x; break;}
for(int x = m; x >= 1; --x)
if(vis[n][x] == state) {ed[i] = x; break;}
}
for(int i = 1; i <= m; ++i) if(!vis[n][i]) con++;
if(con)
printf("0\n%d", con);
else {
int left = 1;
while(left <= m) {
int rmax = left;
for(int i = 1; i <= m; ++i)
if(st[i] <= left) rmax = max(rmax, ed[i]);
con++;
left = rmax + 1;
}
printf("1\n%d", con);
}
return 0;
}