https://www.luogu.org/problemnew/show/P1514
题解:
BFS+排序+剪枝
对第一行的数据排序
按从大到小的顺序进行BFS,记录全部已经走过的格子和当前出发点可以走过的格子,记录当前出发点最后在最后一行的状态
因为可以证明区间一定连续。所以记录左右端点
然后最后一行不断暴力查找当前点为左端点的最大区间,直到完全覆盖
答案不存在时,暴力枚举最后一行是否有不能覆盖的点
/*
*@Author: STZG
*@Language: C++
*/
#include <bits/stdc++.h>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<string>
#include<vector>
#include<bitset>
#include<queue>
#include<deque>
#include<stack>
#include<cmath>
#include<list>
#include<map>
#include<set>
//#define DEBUG
#define RI register int
using namespace std;
typedef long long ll;
//typedef __int128 lll;
const int N=500+10;
const int MOD=1e9+7;
const double PI = acos(-1.0);
const double EXP = 1E-8;
const int INF = 0x3f3f3f3f;
int t,n,m,k;
int ans,cnt,flag,temp;
int a[N][N];
int b[][2]={1,0,0,1,-1,0,0,-1};
int vis[N][N];
int viss[N][N];
char str;
int l[N],r[N];
struct node {
int v;
int x,y;
bool operator <(const node &S)const{
return v>S.v;
}
}e[N];
struct Node {
int x,y;
}s,tmp,f;
void bfs(int x,int y){
queue<Node>q;
s.x=x;
s.y=y;
q.push(s);
memset(vis,0,sizeof(vis));
vis[s.x][s.y]=1;
viss[s.x][s.y]=1;
while(!q.empty()){
f=q.front();
q.pop();
//cout<<f.x<<f.y<<endl;
for(int i=0;i<4;i++){
tmp.x=f.x+b[i][0];
tmp.y=f.y+b[i][1];
if(0<tmp.x&&tmp.x<=n&&0<tmp.y&&tmp.y<=m&&!vis[tmp.x][tmp.y]&&a[f.x][f.y]>a[tmp.x][tmp.y]){
vis[tmp.x][tmp.y]=1;
viss[tmp.x][tmp.y]=1;
q.push(tmp);
}
}
}
}
int main()
{
#ifdef DEBUG
freopen("input.in", "r", stdin);
//freopen("output.out", "w", stdout);
#endif
scanf("%d%d",&n,&m);
//scanf("%d",&t);
//while(t--){}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%d",&a[i][j]);
}
}
cnt=0;
for(int i=1;i<=m;i++){
e[i].v=a[1][i];
e[i].x=1;
e[i].y=i;
}
sort(e+1,e+m+1);
for(int i=1;i<=m;i++){
if(!viss[e[i].x][e[i].y]){
bfs(e[i].x,e[i].y);//cout<<e[i].y<<" "<<r[i]<<" ";
for(int j=1;j<=m;j++){
if(vis[n][j]){
l[i]=j;
break;
}
}
for(int j=1;j<=m;j++){
if(vis[n][j]){
r[i]=j;
}
}
}
}
flag=1;
cnt=0;
for(int j=1;j<=m;j++){
if(!viss[n][j]){
flag=0;
cnt++;
}
}
cout << flag << endl;
if(flag){
int left=1;
while (left<=m){
int maxr=0;
for (int i=1;i<=m;i++)
if (l[i]<=left)
maxr=max(maxr,r[i]);
ans++;
left=maxr+1;
//cout<<left;
}
cout << ans << endl;
}else{
cout << cnt << endl;
}
//cout << "Hello world!" << endl;
return 0;
}