zoukankan      html  css  js  c++  java
  • noip 2010 引水入城(dfs + 贪心)

      非常感到抱歉,由于昨天有点忙,这道题的题解没写,今天补上,争取写的更加详细一点,让大家明白。

      看一下题意:

      在一个遥远的国度,一侧是风景秀美的湖泊,另一侧则是漫无边际的沙漠。该国的行政区划十分特殊,刚好构成一个NNN 行×M imes M×M 列的矩形,如上图所示,其中每个格子都代表一座城市,每座城市都有一个海拔高度。

      为了使居民们都尽可能饮用到清澈的湖水,现在要在某些城市建造水利设施。水利设施有两种,分别为蓄水厂和输水站。蓄水厂的功能是利用水泵将湖泊中的水抽取到所在城市的蓄水池中。

      因此,只有与湖泊毗邻的第111 行的城市可以建造蓄水厂。而输水站的功能则是通过输水管线利用高度落差,将湖水从高处向低处输送。故一座城市能建造输水站的前提,是存在比它海拔更高且拥有公共边的相邻城市,已经建有水利设施。由于第NNN 行的城市靠近沙漠,是该国的干旱区,所以要求其中的每座城市都建有水利设施。那么,这个要求能否满足呢?如果能,请计算最少建造几个蓄水厂;如果不能,求干旱区中不可能建有水利设施的城市数目。

    输入输出格式

      输入格式:

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

       输出格式:

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

    这次我把题意都拿了上来,洛谷有这道题,所以大家可以去洛谷等其他oj看题意以及测试数据,这里就不多说了,主要讲一讲思路。

      从这道题的数据范围来看,n、m<=500非常的大,所以大家需要考虑高效的算法,否则一不容易就会超时,这道题说了水能够从高处向地处流,然后求出最少建造的蓄水厂,

    如果没有就输出‘0’......(还是看题意吧,题意说的非常清楚)。

      不难发现,我们必须要知道湖泊上的城市作为蓄水厂能够流到那里,这需要dfs进行求解,dfs也是需要技巧,需要记录当前位置能够输送到靠近沙漠的那些城市。

      这样我们就得到了湖泊城市与沙漠城市之间的关系,简化了问题,我们再看一看湖泊城市对应的沙漠城市,就发现对应的沙漠城市一定是连续的(想一想,为什么?)如果不连续

    那么就没有解了,就需要输出不能灌溉城市的个数了,对于连续的城市,我们不难想到贪心中的区间覆盖问题,我们需要对区间进行排序,先排序左边(左边小的靠前),

    左边相同看右边(右边大的靠前),这与区间选点的顺序不同(这很重要,否则不能得到最优解),然后按照区间覆盖的方案去做就行了,大家可以去看看其他博客上面区间

    覆盖的解释,不难,然后与这道题对应下,关于区间覆盖的问题,我以后会说,下面就是代码:

    // P1514 
    // dfs + 贪心(区间覆盖问题)
    #include <cstdio> 
    #include <cstring> 
    #include <algorithm>
    using namespace std; 
    
    const int maxn = 500 + 5;
    int N, M, G[maxn][maxn]; 
    
    int L[maxn][maxn], R[maxn][maxn]; // 其中L[1]表第1座靠近湖泊的城市对应的最左边的沙漠城市  
    bool Vis[maxn][maxn], C[maxn];
    
    const int dx[] = {-1, 1, 0, 0}; 
    const int dy[] = {0, 0, -1, 1}; 
    
    void dfs(int x, int y) {
      if (x == N-1) C[y] = 1; 
      for (int i = 0; i < 4; ++i) {
        int x1 = x + dx[i], y1 = y + dy[i]; 
        if (x1 >= 0 && x1 < N && y1 >= 0 && y1 < M && G[x][y] > G[x1][y1]) {
          if (Vis[x1][y1] == 0) {
            Vis[x1][y1] = 1; 
            dfs(x1, y1);
          }
          if (L[x][y] == -1 || (L[x][y] > L[x1][y1] && L[x1][y1] != -1)) L[x][y] = L[x1][y1]; 
          if (R[x][y] == -1 || (R[x][y] < R[x1][y1] && R[x1][y1] != -1)) R[x][y] = R[x1][y1]; 
        }
      }
    }
    
    int City[maxn];
    
    bool cmp(int a, int b) {
      if (L[0][a] != L[0][b]) return L[0][a] < L[0][b]; 
      return R[0][a] > R[0][b];     
    }
    
    void find_pos(int& lastpos, int& rpos) {
      int larpos = 0, rem = rpos; 
      for (int i = rem; i < M; ++i) 
        if (L[0][City[i]] <= lastpos+1) {
          if (R[0][City[i]] > larpos) {
            larpos = R[0][City[i]]; 
            rpos = i;
          }
        }     
        else break; 
      lastpos = larpos; 
    }
    
    int main() { 
      freopen("in.txt", "r", stdin);
      freopen("out.txt", "w", stdout); 
      scanf("%d%d", &N, &M); 
      for (int i = 0; i < N; ++i) 
        for (int j = 0; j < M; ++j) 
          scanf("%d", &G[i][j]); 
      memset(L, -1, sizeof(L)); 
      memset(R, -1, sizeof(R));
      // dfs
      memset(Vis, 0, sizeof(Vis));
      for (int j = 0; j < M; ++j) L[N-1][j] = R[N-1][j] = j;
      for (int j = 0; j < M; ++j) if (!Vis[0][j]) {
        Vis[0][j] = 1; 
        dfs(0, j);  
      }
      // 贪心 区间覆盖问题  
      int cnt = 0; 
      for (int y = 0; y < M; ++y) if (C[y] == 0) ++cnt; 
      if (cnt) printf("0
    %d
    ", cnt); 
      else {
        for (int y = 0; y < M; ++y) City[y] = y; 
        sort(City, City+M, cmp); 
        cnt = 0; 
        int pos = 0, rpos = 0; 
        while (pos != M-1) {
          cnt++; 
          find_pos(pos, rpos); 
        }
        printf("1
    %d
    ", cnt);
      }
      return 0;
    }
  • 相关阅读:
    FZU 2098 刻苦的小芳(卡特兰数,动态规划)
    卡特兰数总结
    FZU 1064 教授的测试(卡特兰数,递归)
    HDU 4745 Two Rabbits(区间DP,最长非连续回文子串)
    Java 第十一届 蓝桥杯 省模拟赛 正整数的摆动序列
    Java 第十一届 蓝桥杯 省模拟赛 反倍数
    Java 第十一届 蓝桥杯 省模拟赛 反倍数
    Java 第十一届 蓝桥杯 省模拟赛 反倍数
    Java 第十一届 蓝桥杯 省模拟赛 凯撒密码加密
    Java 第十一届 蓝桥杯 省模拟赛 凯撒密码加密
  • 原文地址:https://www.cnblogs.com/yifeiWa/p/11220241.html
Copyright © 2011-2022 走看看