首页 > 代码库 > 【搜索+DP】codevs1066-引水入城

【搜索+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 } 

 

【搜索+DP】codevs1066-引水入城