洛谷 P1514 引水入城

题目描述
在一个遥远的国度,一侧是风景秀美的湖泊,另一侧则是漫无边际的沙漠。该国的行政区划十分特殊,刚好构成一个N 行M 列的矩形,如上图所示,其中每个格子都代表一座城市,每座城市都有一个海拔高度。
这里写图片描述
为了使居民们都尽可能饮用到清澈的湖水,现在要在某些城市建造水利设施。水利设施有两种,分别为蓄水厂和输水站。蓄水厂的功能是利用水泵将湖泊中的水抽取到所在城市的蓄水池中。
因此,只有与湖泊毗邻的第1 行的城市可以建造蓄水厂。而输水站的功能则是通过输水管线利用高度落差,将湖水从高处向低处输送。故一座城市能建造输水站的前提,是存在比它海拔更高且拥有公共边的相邻城市,已经建有水利设施。由于第N 行的城市靠近沙漠,是该国的干旱区,所以要求其中的每座城市都建有水利设施。那么,这个要求能否满足呢?如果能,请计算最少建造几个蓄水厂;如果不能,求干旱区中不可能建有水利设施的城市数目。


【题目分析】
BFS+贪心。


【代码】

#include <cstdio>
#include <cstring>
#include <queue>
#include <iostream>
#include <algorithm>
struct line{int l,r;}b[501];
int cnt=0;
using namespace std;
const int inf=0x3f3f3f3f;
int a[501][501],vis[501][501];
int sum[501],n,m;
int mov[4][2]={{1,0},{0,1},{0,-1},{-1,0}};
int bfs(int sx,int sy)
{
    int maxr=-inf,minl=inf;
//    printf("BFS %d \n",sy);
    memset(vis,0,sizeof vis);
    queue <int> qx; queue <int> qy;
    while (!qx.empty()) qx.pop();
    while (!qy.empty()) qy.pop();
    qx.push(sx);qy.push(sy);vis[sx][sy]=1;
    while (!qx.empty())
    {
        int nx=qx.front(); qx.pop();
        int ny=qy.front(); qy.pop();
        if (nx==n)
        {
            sum[ny]++;
            maxr=max(maxr,ny);
            minl=min(minl,ny);
        }
        for (int i=0;i<4;++i)
        {
            int tx=nx+mov[i][0],ty=ny+mov[i][1];
            if (tx<=0||tx>n||ty<=0||ty>m) continue;
            if (!vis[tx][ty]&&a[tx][ty]<a[nx][ny])
            {
                vis[tx][ty]=1;
                qx.push(tx); qy.push(ty);
            }
        }
    }
    if (maxr!=-inf)
    {
        cnt++;
        b[cnt].l=minl;
        b[cnt].r=maxr;
    }
}
bool cmp(line a,line b)
{return a.l==b.l?a.r<a.r:a.l<b.l;}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;++i)
        for (int j=1;j<=m;++j)
            scanf("%d",&a[i][j]);
    for (int i=1;i<=m;++i)
    {
        if (i-1==0)
        {
            if (i+1>m) bfs(1,i);
            else if (a[1][i]>=a[1][i+1]) bfs(1,i);
        }
        else if (i+1>m) {if (a[1][i]>=a[1][i-1]) bfs(1,i);}
        else if (a[1][i]>=a[1][i-1]&&a[1][i]>=a[1][i+1]) bfs(1,i);
    }
    int cant=0;
    for (int i=1;i<=m;++i) if (!sum[i]) cant++;
    if (cant) {printf("0\n%d\n",cant); return 0;}
    sort(b+1,b+cnt+1,cmp);
    int R=0,i=1,ans=1;
    for (;i<=n&&b[i].l==1;++i) R=max(R,b[i].r);
    while (i<=cnt)
    {
        ans++;
        int tmp=R;
        for (;i<=cnt;++i)
        {
            if (b[i].l<=tmp+1) R=max(R,b[i].r);
            else break;
        }
        if (R==m) break;
    }
    printf("1\n%d\n",ans);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值