zoukankan      html  css  js  c++  java
  • 引水入城

    【题目描述】

     

    在一个遥远的国度,一侧是风景秀美的湖泊,另一侧则是漫无边际的沙漠。该国的行政区划十分特殊,刚好构成一个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)。
        反思教训:
            思维应发散,经常考虑能不能用其他方法来解决这个难点。
    */
  • 相关阅读:
    hdoj2187:悼念512汶川大地震遇难同胞 (贪心)
    2.0其它之Transform详解,以及UIElement和FrameworkElement的常用属性
    2.0外观之样式, 模板, 视觉状态和视觉状态管理器
    2.0图形之Ellipse, Line, Path, Polygon, Polyline, Rectangle
    2.0控件之ListBox, MediaElement, MultiScaleImage, PasswordBox, ProgressBar, RadioButton
    2.0画笔之SolidColorBrush, ImageBrush, VideoBrush, LinearGradientBrush, RadialGradientBrush
    2.0图形之基类System.Windows.Shapes.Shape
    2.0交互之鼠标事件和键盘事件
    2.0控件之ScrollViewer, Slider, StackPanel, TabControl, TextBlock, TextBox, ToggleButton
    2.0交互之InkPresenter(涂鸦板)
  • 原文地址:https://www.cnblogs.com/Ackermann/p/5618178.html
Copyright © 2011-2022 走看看