只能给超链接了
https://www.luogu.org/problem/show?pid=1514
解释:bfs+dp枚举第一行每个点进行bfs,算出每个点能扩展到最后一行的左端点与右端点。这里有一个剪枝:如果该点的海拔>=左右两点和下面的点的海拔那么可选,其它情况选了也是重复搜索。
至于左端点与右端点…首先我们要证明如果输出的是1的话,那么扩展到最后一行一定是连续的一段区间。
对于最后一行的一个点i,如果它的左边和右边都到达了,而它却无法到达,那么海拔比它高的只有它的上面了。设它上面的点为j,如果我们想到达j,那么我们仍然只能从j的上面到达,因为如果是由j的左右到达的话,那么i点的左右必定也能到达。一次类推,发现i所在的一列就变成了一个“屏障”,左边的点流不到右边,右边流不到左边,只有这一列能流向两边…与假设违背啊...
所以最后有了许多线段,转换成了区间覆盖问题,贪心法求解。
#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #include <queue> using namespace std; int c[4][2]={{1,0},{-1,0},{0,-1},{0,1}}; int a[510][510]; bool d[510][510],e[510][510]; struct hh { int x,y; }p[510]; int cmp(hh a,hh b) { if (a.x==b.x) return a.y<b.y; else return a.x<b.x; } int main() { int n,m,i,j; scanf("%d%d",&n,&m); for (i=1;i<=n;i++) for (j=1;j<=m;j++) scanf("%d",&a[i][j]); for (j=1;j<=m;j++) if (a[1][j]>=a[1][j+1] && a[1][j]>=a[1][j-1] && a[2][j]<a[1][j]) { memset(e,0,sizeof(e)); queue <int> x,y; d[1][j]=true; x.push(1); y.push(j); p[j].x=2100000; while (!x.empty()) { int u=x.front(),v=y.front(); if (u==n) { p[j].x=min(p[j].x,v); p[j].y=max(p[j].y,v); } x.pop();y.pop(); for (i=0;i<=3;i++) { int ii=c[i][0]+u,jj=c[i][1]+v; if (ii>0 && jj>0 && ii<=n && jj<=m && a[ii][jj]<a[u][v] && !e[ii][jj]) { e[ii][jj]=true; d[ii][jj]=true; x.push(ii); y.push(jj); } } } } int dd=0; for (i=1;i<=m;i++) if (!d[n][i]) dd++; if (dd) { printf("0\n%d",dd); return 0; } printf("1\n"); sort(p+1,p+1+m,cmp); int cur=1,ans_cnt=0; i=2; while(p[cur].y<m) { int maxk=cur; while(i<=m&&p[i].x<=p[cur].y+1) { if(p[i].y>p[maxk].y) maxk=i; i++; } cur=maxk; ans_cnt++; } printf("%d\n",ans_cnt); }