引水入城

Posted 【對策局】

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了引水入城相关的知识,希望对你有一定的参考价值。

【题目描述】

 技术分享

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

【输入描述】

输入的每行中两个数之间用一个空格隔开。输入的第一行是两个正整数N和M,表示矩形的规模。接下来N行,每行M个正整数,依次代表每座城市的海拔高度。

【输出描述】

输出有两行。如果能满足要求,输出的第一行是整数1,第二行是一个整数,代表最少建造几个蓄水厂;如果不能满足要求,输出的第一行是整数0,第二行是一个整数,代表有几座干旱区中的城市不可能建有水利设施。

【样例输入】

2 5

9 1 5 4 3

8 7 6 1 2

【样例输出】

1

1

【数据范围及提示】

某一样例说明:

技术分享

技术分享

源代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#define INF 100000000
using namespace std;
struct Node
{
    int x,y;
}h[300001];
struct node
{
    int left,right;
}F[501];
int m,n,now,ans(0),num[501],i[501][501];
const int sum[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
bool f[501][501]={0};
void BFS() //本蒟蒻终于会BFS了。
{
    int head(0),tail(0);
    for (int a=1;a<=m;a++)
    {
        f[1][a]=true;
        h[++tail].x=1;
        h[tail].y=a;
    }
    while (head<tail)
    {
        Node t=h[++head]; //新奇的结构体用法。
        for (int a=0;a<4;a++) //此数组的懒惰用法应值得借鉴。
        {
            Node s;
            s.x=t.x+sum[a][0];
            s.y=t.y+sum[a][1];
            if (s.x<1||s.x>n||s.y<1||s.y>m)
              continue;
            if (i[s.x][s.y]>=i[t.x][t.y])
              continue;
            if (f[s.x][s.y])
              continue;
            f[s.x][s.y]=true;
            h[++tail]=s;
        }
    }
}
void DFS(int x,int y) //DFS找最小左区间和最大右区间。
{
    f[x][y]=true;
    if (x==n)
    {
        F[now].left=min(F[now].left,y);
        F[now].right=max(F[now].right,y);
    }
    for (int a=0;a<4;a++)
    {
        Node t;
        t.x=x+sum[a][0];
        t.y=y+sum[a][1];
        if (t.x<1||t.x>n||t.y<1||t.y>m)
          continue;
        if (i[t.x][t.y]>=i[x][y])
          continue;
        if (!f[t.x][t.y])
          DFS(t.x,t.y);
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int a=1;a<=n;a++)
      for (int b=1;b<=m;b++)
        scanf("%d",&i[a][b]);
    BFS();
    for (int a=1;a<=m;a++)
      if (!f[n][a])
        ans++;
    if (ans)
    {
          printf("0\n%d",ans);
          return 0; //还能这么玩。
    }
    printf("1\n");
    for (int a=1;a<=m;a++)
    {
        memset(f,0,sizeof(f)); //全新的开始。
        now=a; //全局变量的应用。
        F[now].left=m+1;
        F[now].right=0;
        DFS(1,a);
    }
    num[0]=0; //num[i]表示1~i所需的线段数最小值。
    for (int a=1;a<=m;a++) //线段覆盖DP。
    {
        num[a]=INF;
        for (int b=1;b<=m;b++)
          if (a>=F[b].left&&a<=F[b].right)
            num[a]=min(num[a],num[F[b].left-1]+1);
    }
    printf("%d",num[m]);
    return 0;
}

以上是关于引水入城的主要内容,如果未能解决你的问题,请参考以下文章

NOIP2010 引水入城

luoguP1514 引水入城 题解(NOIP2010)

P1514 引水入城

P1514 引水入城

CCF(引水入城:60分):最大流+ISAP算法

CODEVS 1066/洛谷 P1514引水入城