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

【题目大意】

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

一个N行M列的矩形,如上图所示,其中每个格子都代表一座城 市,每座城市都有一个海拔高度。现在要在某些城市建造水利设施。水利设施有两种,分别为蓄水厂和输水站。蓄水厂的功能是利用水泵将湖泊中的水抽取到所在城市的 蓄水池中。因此,只有与湖泊毗邻的第1行的城市可以建造蓄水厂。而输水站的功能则是通 过输水管线利用高度落差,将湖水从高处向低处输送。故一座城市能建造输水站的前提,是存在比它海拔更高且拥有公共边的相邻城市,已经建有水利设施。 由于第N行的城市靠近沙漠,是该国的干旱区,所以要求其中的每座城市都建有水利设施。那么,这个要求能否满足呢?如果能,请计算最少建造几个蓄水厂;如果不能,求干旱区中不可能建有水利设施的城市数目。

【思路】

从湖泊边的每一个城市跑DFS,得到能抵达沙漠边的哪些城市。在沙漠旁所有城市都可以被访问到的情况下,可以证明由湖泊旁的一个城市到达的沙漠旁城市是连续的。

证明:如果不连续那么一定有另一个点b可以到达本点a不能到达的地方,那么两个点的路径一定会有一个交点,a就一定可以通过这个交点到达所谓不能到达的地方,所以假设不成立。

问题转化为了给出一些线段,求用最少的线段数覆盖一个区间。DP一下就好了。

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=+;
struct node
{
int l,r;
bool operator < (const node&x) const
{
return l<x.l;
}
}arriv[MAXN];
int m,n,h[MAXN][MAXN],vis[MAXN][MAXN];
int f[MAXN],cover[MAXN];
int dx[]={,-,,};
int dy[]={,,,-}; void init()
{
scanf("%d%d",&m,&n);
for (int i=;i<=m;i++)
for (int j=;j<=n;j++) scanf("%d",&h[i][j]);
} void dfs(int x,int y,int fr)
{
vis[x][y]=fr;
if (x==m)
{
arriv[fr].l=min(arriv[fr].l,y);
arriv[fr].r=max(arriv[fr].r,y);
cover[y]=;
}
for (int i=;i<;i++)
{
int xx=x+dx[i],yy=y+dy[i];
if (xx<= || xx>m || yy<= || yy>n) continue;
if (h[xx][yy]<h[x][y] && vis[xx][yy]!=fr) dfs(xx,yy,fr);
}
} void solve()
{
memset(cover,,sizeof(cover));
memset(vis,,sizeof(vis));
for (int i=;i<=n;i++)
{
arriv[i].l=MAXN,arriv[i].r=-;
dfs(,i,i);
} int flag=,rem=;
for (int i=;i<=n;i++) if (!cover[i]){flag=;rem++;} if (flag)
{
puts("");
sort(arriv+,arriv+n+);
for (int i=;i<=n;i++) f[i]=MAXN;
f[]=;
for (int i=;i<=n;i++)
{
int l=arriv[i].l,r=arriv[i].r;
for (int j=l-;j<=r;j++) f[r]=min(f[r],f[j]+);
}
printf("%d",f[n]);
}
else printf("0\n%d",rem);
} int main()
{
init();
solve();
return ;
}
上一篇:ALGO-117_蓝桥杯_算法训练_友好数


下一篇:ptyhon技能树及其学习资源