题目链接:https://www.luogu.com.cn/problem/P1514
注意这道题只能用DFS而不能直接用dp,因为在每一个格子,没有固定的方向,而是上下左右都可以走。但其中有dp的思想:不断更新l和r。
这道题中首先判断干旱区所有的城市能否都能建有水利工程。则先让第一行的每一个城市都有水利工程,然后进行遍历,看最后一行的所有点能不能都被走到,如果有走不到的,则说明不行,记录走不到的个数,输出即可。
如果都能走到,则需要考虑第一行选哪几个使得能将最后一行全部覆盖过来。那么在刚才遍历的时候,可以不断更新l[][],r[][](详见代码),直到从l[n][]和r[n][]更新至l[1][]和r[1][]。现在l[1][i]和r[1][i]中分别存第一行第i个如果选的话,能灌溉最后一行[l,r]这个区间的城市。然后用线段覆盖思想来做即可。(详见while)
AC代码:
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 using namespace std; 5 const int N=505; 6 int n,m; 7 int vis[N][N],g[N][N],l[N][N],r[N][N]; 8 int _x[4]={1,0,0,-1}; 9 int _y[4]={0,1,-1,0}; 10 bool judge(int x,int y){ 11 if(x<1||x>n) return 0; 12 if(y<1||y>m) return 0; 13 return 1; 14 } 15 void DFS(int x,int y){ 16 vis[x][y]=1; 17 for(int i=0;i<4;i++){ 18 int xx=x+_x[i],yy=y+_y[i]; 19 if(!judge(xx,yy)) continue; 20 if(g[xx][yy]>=g[x][y]) continue; 21 if(!vis[xx][yy]) DFS(xx,yy); 22 l[x][y]=min(l[x][y],l[xx][yy]); 23 r[x][y]=max(r[x][y],r[xx][yy]); 24 } 25 } 26 int main(){ 27 memset(l,0x3f3f3f,sizeof(l)); 28 scanf("%d%d",&n,&m); 29 for(int i=1;i<=n;i++) 30 for(int j=1;j<=m;j++) scanf("%d",&g[i][j]); 31 for(int i=1;i<=m;i++) l[n][i]=r[n][i]=i; 32 for(int i=1;i<=m;i++) if(!vis[1][i]) DFS(1,i); 33 int flag=0,ans=0; 34 for(int i=1;i<=m;i++){ 35 if(!vis[n][i]){ 36 flag=1; 37 ans++; 38 } 39 } 40 if(flag){ 41 printf("0 %d",ans); 42 return 0; 43 } 44 int low=1; 45 while(low<=m){ 46 int maxx=0; 47 for(int i=1;i<=m;i++){ 48 if(l[1][i]<=low) maxx=max(maxx,r[1][i]); 49 } 50 ans++; 51 low=maxx+1; 52 } 53 printf("1 %d",ans); 54 return 0; 55 }