洛谷P1514 引水入城(深搜,贪心)

洛谷P1514 引水入城(深搜,贪心)

题目描述

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

输入输出格式

输入格式:

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

输出格式:

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

输入输出样例

【输入样例1】

2 5
9 1 5 4 3
8 7 6 1 2

【输入样例2】

3 6
8 4 5 6 4 4
7 3 4 3 3 3
3 2 2 1 1 2

【输出样例1】

1
1

【输出样例2】

1
3

说明

【样例1 说明】
只需要在海拔为9 的那座城市中建造蓄水厂,即可满足要求。
【样例2 说明】
上图中,在3 个粗线框出的城市中建造蓄水厂,可以满足要求。以这3 个蓄水厂为源头
在干旱区中建造的输水站分别用3 种颜色标出。当然,建造方法可能不唯一。
【数据范围】

解题分析

首先构建图,将所有城市与其四周高度比它低的城市之间添加一条有向边。
从第一行的入度为0的城市出发进行深搜,在深搜过程中需要记录两个数据:used[i][j]表示城市(i, j)有没有访问过,vis[i][j]表示从城市(i, j)出发所能覆盖干旱区的区间。通过记忆化搜索方法搜索。
当搜索完之后,如果有干旱区城市的used为0,则这些城市不可能见水利设施。

如果干旱区的城市都可以建水利设施,则从第一行的某个城市出发所能覆盖干旱区的城市一定是一个连续的区域(即在前面所求的的区间,可以通过反证法证明,这里不再赘述),因此只要判断至少需要几个区间能覆盖所有的干旱区的城市,可以用贪心法实现。

#include 
   
   
    
    
#include 
    
    
     
     
#include 
     
     
      
      
#include 
      
      
       
       
#include 
       
       
         #include 
        
          #include 
         
           using namespace std; #define INF 0x7fffffff #define N 502 int n, m, city[N][N], indegree[N][N] = {0}; int cnt = 0, dir[4][2]={{1,0}, {-1, 0}, {0, 1}, {0, -1}}; struct point{ int x; int y; }; struct node{ point to[4]; int to_size; node():to_size(0){ } void add(int x, int y){ to[to_size].x = x; to[to_size].y = y; to_size++; indegree[x][y]++; } }e[N][N]; struct node1{ int left; int right; node1():left(INF), right(-1){ } }vis[N][N], vis1[N]; int used[N][N]; void get_i(int &x){ char ch = getchar(); x = 0; while(!isdigit(ch)) ch = getchar(); while(isdigit(ch)){ x = x * 10 + ch - '0'; ch = getchar(); } } bool cmp(node1 n1, node1 n2){ if(n1.left != n2.left) return n1.left < n2.left; return n1.right > n2.right; } void dfs(int x, int y){ int i, to_x, to_y; node n1 = e[x][y]; for(i=0; i 
          
            =0 && di 
           
             =0 && dj 
            
              city[di][dj]) e[i][j].add(di, dj); } } } for(i=0; i 
              
             
            
           
          
         
       
      
      
     
     
    
    
   
   


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值