题目链接
解题思路:
综合考察了搜索和区间合并。
难点在于记录最后一行区间的左右端点,还有从第一行开始搜时,注意优化一下,并不是第一行的每列作为起点开始搜,而是比左右端点都大的列开始搜,可以节省时间。
区间合并注意排序。
include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxv=233233233;
int map[510][510],vis[510][510];
int flag[510];
int g[][2]={-1,0,1,0,0,1,0,-1};//前进的四个方向
int n,m;
struct qujian{//区间
int l,r;
}c[510];
bool cmp(qujian A,qujian B){//区间合并,首先升序
if(A.l==B.l) return A.r<B.r;
return A.l<B.l;
}
void dfs(int x,int y,int index){//坐标x,y,以及第一行开始搜索的点index
if(x==n){
c[index].l=min(c[index].l,y);//区间标记
c[index].r=max(c[index].r,y);
flag[y]=1;
}
for(int i=0;i<4;i++){
int nx=x+g[i][0];
int ny=y+g[i][1];
if(nx<1||nx>n||ny<1||ny>m) continue;
if(!vis[nx][ny]&&map[x][y]>map[nx][ny]){
vis[nx][ny]=1;
dfs(nx,ny,index);
}
}
}
//int test(){
// for(int i=1;i<=m;i++){
// if(!vis[n][i]) return 1;//未访问完
// }
// return 0;
//}
int main(int argc, char** argv) {
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%d",&map[i][j]);
if(i==1) c[j].l=maxv;
}
}
for(int i=1;i<=m;i++){
if(map[1][i]>=map[1][i-1]&&map[1][i]>=map[1][i+1]){//优化1,从第一行选择满足条件的点开始往下搜
memset(vis,0,sizeof(vis));
dfs(1,i,i);
}
}
int cnt=0;
for(int j=1;j<=m;j++){
if(!flag[j]) cnt++;//如果flag[j]==0,说明最后一行第j列没有被访问到。
}
if(cnt==0){
sort(c+1,c+m+1,cmp);//升序
int len=m;
while(c[m].l==maxv) --m;//除去之前未访问的值
// for(int i=1;i<=m;i++)
// printf("%d %d\n",c[i].l,c[i].r);
//排序之后区间合并
int i1=1,tr=1,ans=0;//区间左端点,右端点,累计的值ans
while(tr<=len){
int temp=0;
while(c[i1].l<=tr){
temp=max(temp,c[i1].r);
i1++;
}
tr=temp+1;
ans+=1;
}
printf("1\n%d\n",ans);
}
else{
printf("0\n%d\n",cnt);
}
return 0;
}