• 引水入城


    【题目描述】

     

    在一个遥远的国度,一侧是风景秀美的湖泊,另一侧则是漫无边际的沙漠。该国的行政区划十分特殊,刚好构成一个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 1000000000
    using namespace std;
    struct Node1
    {
        int X,Y;
    }Q[250001];
    struct Node2
    {
        int Left,Right;
    }F[501];
    int m,n,ans(0),Now,i[501][501],Num[501],x[4]={-1,1,0,0},y[4]={0,0,-1,1};
    bool f[501][501]={0};
    void BFS()
    {
        int Head(0),Tail(0);
        for (int a=1;a<=m;a++)
        {
            f[1][a]=true;
            Q[++Tail].X=1;
            Q[Tail].Y=a;
        }
        while (Head<Tail)
        {
            Node1 t=Q[++Head]; //新奇的结构体用法。
            for (int a=0;a<4;a++)
            {
                Node1 T;
                T.X=t.X+x[a];
                T.Y=t.Y+y[a];
                if (T.X<1||T.X>n||T.Y<1||T.Y>m||i[T.X][T.Y]>=i[t.X][t.Y]||f[T.X][T.Y])
                  continue;
                f[T.X][T.Y]=true;
                Q[++Tail]=T;
            }
        }
    }
    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++)
        {
            int t1=X+x[a];
            int t2=Y+y[a];
            if (t1<1||t1>n||t2<1||t2>m||i[t1][t2]>=i[X][Y]||f[t1][t2])
              continue;
            DFS(t1,t2);
        }
    }
    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
    %d",ans);
            return 0;
        }
        for (int a=1;a<=m;a++)
        {
            memset(f,false,sizeof(f)); //全新的开始。
            Now=a; //全局变量的应用。
            F[a].Left=m+1;
            F[a].Right=0;
            DFS(1,a);
        }
        Num[0]=0;
        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("1
    %d",Num[m]);
        return 0;
    }
    
    /*
        很全面的一道搜索题,挺有意思的。
        思路:
            先设所有河边城市都修建水站,BFS查看能不能覆盖沙漠城市;
            再DFS每个河边城市,并记录它们最小左边界和最大右边界;
            最后线段覆盖DP一下,求出最少应建造多少水站。
        线段覆盖型动态规划:
            设Num[i]表示覆盖1~i所需最少的线段数,则有状态转移方程(遍历所有线段):
                Num[i]=min(Num[i],Num[F[k].Left-1]+1),(F[k].Left <= i <= F[k].Right)。
        反思教训:
            思维应发散,经常考虑能不能用其他方法来解决这个难点。
    */
  • 相关阅读:
    MVC中添加执行统计功能
    SVN 全局忽略列表
    WebApi当中微软又犯了一次2
    SQL性能更总
    【懒人专用】快速构建Web请求
    js中模拟多个字母的split
    分页起始位置的懒汉判断方法
    文档摆放
    转: 多线程环境下调用 HttpWebRequest 并发连接限制
    bash命令根据历史记录补全
  • 原文地址:https://www.cnblogs.com/Ackermann/p/5618178.html
Copyright © 2020-2023  润新知