是一道十分巧妙的题目。
GO:传送门
首先考虑第一问:
能否满足要求,用搜索遍历一下地图即可。
难就难在第二问:如何求最小蓄水站数量?
我们从河边开始走,从一个点(i,j)开始,由水流方向dfs,处理出每个节点到最底端最多能覆盖多长的一段路径。
我们可以证明,如果有解,这段路径是连续的:
如果不连续,那么在沙漠那块必定存在一个空间,使得不连续的那段路径将其包含,又知有解,所以必定存在一条路径使得那个空间与水源联通,与假设矛盾。
我们只要处理出水源处每一个点能到达的区间,然后做一个线段覆盖即可。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=510; 4 int n,m; 5 int val[N][N]; 6 int l[N][N],r[N][N]; 7 int vis[N][N]; 8 int px[5]{1,0,-1,0},py[5]{0,-1,0,1}; 9 struct sig{ 10 int a,b; 11 }sg[N]; 12 bool cmp(sig x,sig y){ 13 return x.a>y.a; 14 } 15 void dfs(int x,int y){ 16 vis[x][y]=1; 17 for(int i=0;i<=3;i++){ 18 int tx=x+px[i],ty=y+py[i]; 19 if(tx>n||tx<=0||ty>m||ty<=0) continue; 20 if(val[tx][ty]<val[x][y]){ 21 if(!vis[tx][ty]) dfs(tx,ty); 22 l[x][y]=min(l[x][y],l[tx][ty]); 23 r[x][y]=max(r[x][y],r[tx][ty]); 24 } 25 } 26 } 27 int read(){ 28 int x=0,f=1; 29 char c=getchar(); 30 while(!isdigit(c)){ 31 if(c=='-') f=-1; 32 c=getchar(); 33 } 34 while(isdigit(c)){ 35 x=x*10+c-'0'; 36 c=getchar(); 37 } 38 return x*f; 39 } 40 int main(){ 41 n=read();m=read(); 42 for(int i=1;i<=n;i++){ 43 for(int j=1;j<=m;j++){ 44 val[i][j]=read(); 45 } 46 } 47 memset(l,0x3f,sizeof(l)); 48 memset(r,0,sizeof(r)); 49 for(int i=1;i<=m;i++){ 50 l[n][i]=r[n][i]=i; 51 } 52 for(int i=1;i<=m;i++){ 53 if(!vis[1][i]) dfs(1,i); 54 } 55 int sum=0; 56 for(int i=1;i<=m;i++){ 57 if(!vis[n][i]) sum++; 58 } 59 if(sum){ 60 printf("0\n%d",sum); 61 return 0; 62 } 63 int ll=1; 64 while(ll<=m){ 65 int rr=0; 66 for(int i=1;i<=m;i++){ 67 if(l[1][i]<=ll) rr=max(rr,r[1][i]); 68 } 69 sum++; 70 ll=rr+1; 71 } 72 printf("1\n%d",sum); 73 return 0; 74 }