我承认我有点懒(洛谷已经发过题解了,但我发誓要坚持写博客)
这道题坑了我3天……
首先一看就与染色问题类似,果断BFS(写DFS炸了)
先将最上面(靠近水)的一行全部扔进队列里,做一遍BFS
再对最下面(远离水)的一行进行扫描,如果发现有点搜索不到,输出0并统计个数退出(很好说明:如果全部修建都无法完成那么使用更少的点是不可能的)
如果可以,就进行第二遍BFS
把第一行每个点分别扔进队列,搜索出它在最下面的可以供水的区间
等等,为什么是区间?
这个很好证明,有多位大佬已经详细证明,我简单说一下
如果这个区间间断了,那么这个间断的点就会比周围的点海拔都高,那么就会产生无解的情况,因为已经证明有解,所以不可能出现这种情况
所以,我们统计所有的区间,做一遍区间覆盖即可
方法很多,DP或者贪心
我打的是贪心,记录最优的区间尾端点
具体看代码
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #define maxn 505 using namespace std; inline void read(int &x) { x=0; char ch=getchar(); while (ch<'0'||ch>'9') ch=getchar(); while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); } struct data { int x,y; }a[maxn]; //记录区间 int comp(data a,data b) { return a.x<b.x; } const int fx[4]={0,1,0,-1},fy[4]={1,0,-1,0}; int map[maxn][maxn],n,m,i,j,q[maxn*maxn*2+10][2],tot,ans,k,t1,t2; bool f[maxn][maxn],flag=0; int main() { read(n); read(m); for (i=1;i<=n;++i) for (j=1;j<=m;++j) read(map[i][j]); memset(f,true,sizeof(f)); int head=0,tail=0; for (j=1;j<=m;++j) f[1][j]=0,q[++tail][0]=1,q[tail][1]=j; while (head++<tail) //第一遍BFS判断是否有解 { for (i=0;i<4;++i) { int xx=q[head][0]+fx[i],yy=q[head][1]+fy[i]; if (f[xx][yy]&&xx>0&&yy>0&&xx<=n&&yy<=m&&map[xx][yy]<map[q[head][0]][q[head][1]]) { f[xx][yy]=0; q[++tail][0]=xx; q[tail][1]=yy; } } } for (j=1;j<=m;++j) if (f[n][j]) { flag=1; tot++; } if (flag) { puts("0"); printf("%d",tot); return 0; } for (j=1;j<=m;++j) //对每个点都做一遍BFS,由于数据不大,可以水过 { memset(f,true,sizeof(f)); f[1][j]=0; head=0; tail=1; q[1][0]=1; q[1][1]=j; while (head++<tail) { for (i=0;i<4;++i) { int xx=q[head][0]+fx[i],yy=q[head][1]+fy[i]; if (f[xx][yy]&&xx>0&&xx<=n&&yy>0&&yy<=m&&map[xx][yy]<map[q[head][0]][q[head][1]]) { q[++tail][0]=xx; q[tail][1]=yy; f[xx][yy]=0; } } } t1=t2=0; for (i=1;i<=m;++i) if (!f[n][i]) { t1=i; break; } if (!t1) continue; for (;i<=m+1;++i) if (f[n][i]) { t2=i-1; break; } a[++k].x=t1; a[k].y=t2; //记录可以到达的区间 } sort(a+1,a+k+1,comp); puts("1"); i=1; int last=1; while (last<=m) { int t=0; while (a[i].x<=last) t=max(a[i++].y,t); last=t+1; ans++; } //贪心跑一遍区间覆盖模板 printf("%d",ans); return 0; }
难度不大吧,就是很 烦