【搜索+DP】codevs1066-引水入城
【题目大意】
一个N行M列的矩形,如上图所示,其中每个格子都代表一座城 市,每座城市都有一个海拔高度。现在要在某些城市建造水利设施。水利设施有两种,分别为蓄水厂和输水站。蓄水厂的功能是利用水泵将湖泊中的水抽取到所在城市的 蓄水池中。因此,只有与湖泊毗邻的第1行的城市可以建造蓄水厂。而输水站的功能则是通 过输水管线利用高度落差,将湖水从高处向低处输送。故一座城市能建造输水站的前提,是存在比它海拔更高且拥有公共边的相邻城市,已经建有水利设施。 由于第N行的城市靠近沙漠,是该国的干旱区,所以要求其中的每座城市都建有水利设施。那么,这个要求能否满足呢?如果能,请计算最少建造几个蓄水厂;如果不能,求干旱区中不可能建有水利设施的城市数目。
【思路】
从湖泊边的每一个城市跑DFS,得到能抵达沙漠边的哪些城市。在沙漠旁所有城市都可以被访问到的情况下,可以证明由湖泊旁的一个城市到达的沙漠旁城市是连续的。
证明:如果不连续那么一定有另一个点b可以到达本点a不能到达的地方,那么两个点的路径一定会有一个交点,a就一定可以通过这个交点到达所谓不能到达的地方,所以假设不成立。
问题转化为了给出一些线段,求用最少的线段数覆盖一个区间。DP一下就好了。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 const int MAXN=500+50; 7 struct node 8 { 9 int l,r; 10 bool operator < (const node&x) const 11 { 12 return l<x.l; 13 } 14 }arriv[MAXN]; 15 int m,n,h[MAXN][MAXN],vis[MAXN][MAXN]; 16 int f[MAXN],cover[MAXN]; 17 int dx[4]={1,-1,0,0}; 18 int dy[4]={0,0,1,-1}; 19 20 void init() 21 { 22 scanf("%d%d",&m,&n); 23 for (int i=1;i<=m;i++) 24 for (int j=1;j<=n;j++) scanf("%d",&h[i][j]); 25 } 26 27 void dfs(int x,int y,int fr) 28 { 29 vis[x][y]=fr; 30 if (x==m) 31 { 32 arriv[fr].l=min(arriv[fr].l,y); 33 arriv[fr].r=max(arriv[fr].r,y); 34 cover[y]=1; 35 } 36 for (int i=0;i<4;i++) 37 { 38 int xx=x+dx[i],yy=y+dy[i]; 39 if (xx<=0 || xx>m || yy<=0 || yy>n) continue; 40 if (h[xx][yy]<h[x][y] && vis[xx][yy]!=fr) dfs(xx,yy,fr); 41 } 42 } 43 44 void solve() 45 { 46 memset(cover,0,sizeof(cover)); 47 memset(vis,0,sizeof(vis)); 48 for (int i=1;i<=n;i++) 49 { 50 arriv[i].l=MAXN,arriv[i].r=-1; 51 dfs(1,i,i); 52 } 53 54 int flag=1,rem=0; 55 for (int i=1;i<=n;i++) if (!cover[i]){flag=0;rem++;} 56 57 if (flag) 58 { 59 puts("1"); 60 sort(arriv+1,arriv+n+1); 61 for (int i=1;i<=n;i++) f[i]=MAXN; 62 f[0]=0; 63 for (int i=1;i<=n;i++) 64 { 65 int l=arriv[i].l,r=arriv[i].r; 66 for (int j=l-1;j<=r;j++) f[r]=min(f[r],f[j]+1); 67 } 68 printf("%d",f[n]); 69 } 70 else printf("0\n%d",rem); 71 } 72 73 int main() 74 { 75 init(); 76 solve(); 77 return 0; 78 }