【NOIP2010】引水入城
以前一直以为是什么高端DP,看了题解才发现是水题,老是这样看题解才能写出来到赛场上怎么办嘛QAQ
原题:
在一个遥远的国度,一侧是风景秀美的湖泊,另一侧则是漫无边际的沙漠。该国的行政
区划十分特殊,刚好构成一个 N 行 M 列的矩形,如上图所示,其中每个格子都代表一座城 市,每座城市都有一个海拔高度。
为了使居民们都尽可能饮用到清澈的湖水,现在要在某些城市建造水利设施。水利设施 有两种,分别为蓄水厂和输水站。蓄水厂的功能是利用水泵将湖泊中的水抽取到所在城市的 蓄水池中。因此,只有与湖泊毗邻的第 1 行的城市可以建造蓄水厂。而输水站的功能则是通 过输水管线利用高度落差,将湖水从高处向低处输送。故一座城市能建造输水站的前提,是 存在比它海拔更高且拥有公共边的相邻城市,已经建有水利设施。
由于第 N 行的城市靠近沙漠,是该国的干旱区,所以要求其中的每座城市都建有水利 设施。那么,这个要求能否满足呢?如果能,请计算最少建造几个蓄水厂;如果不能,求干 旱区中不可能建有水利设施的城市数目。
首先可以先假设第一行的所有格子都建站了,用bfs即可求出是否能把最后一行完全覆盖以及如果不能完全覆盖没有覆盖到的格子有几个
然后在用一个bfs求出如果在第一行第i个格子建站能在最后一行上覆盖区间的左端点和右端点,容易证明如果在第一行某点建站,在最后一行一定是连续覆盖一个区间
然后区间覆盖dp,if(i>=left[j] && i<=right[j]) f[i]=min(f[i],f[left[j]-1]+1)
需要有一个特判,就是只有一行的情况(如果在第一次bfs把第一行每个点入队的同时也标记上的话似乎就不用搞这个特判)
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
int read(){int z=,mark=; char ch=getchar();
while(ch<''||ch>''){if(ch=='-')mark=-; ch=getchar();}
while(ch>=''&&ch<=''){z=(z<<)+(z<<)+ch-''; ch=getchar();}
return z*mark;
}
int fx[]={,-,,},fy[]={,,,-};
int m,n,a[][];
int visited[][];
int dui[],tou=;
int ans;
int fleft[],fright[];
int f[];
int bfs1(){
memset(visited,,sizeof(visited));
for(int i=;i<=n;i++) dui[++tou]=i-;
for(int k=;k<=tou;k++){
int x=dui[k]/n+,y=dui[k]%n+;
for(int i=;i<;i++)if(!visited[x+fx[i]][y+fy[i]] && a[x][y]>a[x+fx[i]][y+fy[i]]){
visited[x+fx[i]][y+fy[i]]=-;
dui[++tou]=(x+fx[i]-)*n+y+fy[i]-;
}
}
int ge=;
for(int i=;i<=n;i++) if(!visited[m][i]) ge++;
return ge;
}
void bfs2(int _s){
dui[tou=]=_s-;
for(int k=;k<=tou;k++){
int x=dui[k]/n+,y=dui[k]%n+;
for(int i=;i<;i++)if(visited[x+fx[i]][y+fy[i]]!=_s && a[x][y]>a[x+fx[i]][y+fy[i]]){
visited[x+fx[i]][y+fy[i]]=_s;
dui[++tou]=(x+fx[i]-)*n+y+fy[i]-;
}
}
for(int i=;i<=n;i++) if(visited[m][i]==_s){ fleft[_s]=i;
for(int j=i+;j<=n+;j++) if(visited[m][j]!=_s){ fright[_s]=j-;//注意这里如果枚举到n就有可能n也被覆盖了,然后fright就是0
break;
}
break;
}
}
int main(){
//freopen("ddd.in","r",stdin);
freopen("flow.in","r",stdin);
freopen("flow.out","w",stdout);
memset(f,,sizeof(f));
cin>>m>>n;
for(int i=;i<=m;i++)
for(int j=;j<=n;j++)
a[i][j]=read();
for(int i=;i<=m+;i++) a[i][]=,a[i][n+]=;
for(int i=;i<=n+;i++) a[][i]=,a[m+][i]=;
if(ans=bfs1()){ cout<<((m==) ? : )<<endl<<ans<<endl; return ;}//去你大爷的特判,这里有一行的情况
for(int i=;i<=n;i++) bfs2(i);
f[]=;
for(int i=;i<=n;i++)
for(int j=;j<=n;j++)
if(i>=fleft[j] && i<=fright[j])
f[i]=min(f[i],f[fleft[j]-]+);
cout<<<<endl<<f[n]<<endl;
return ;
}
【NOIP2010】引水入城的更多相关文章
- 521. [NOIP2010] 引水入城 cogs
521. [NOIP2010] 引水入城 ★★★ 输入文件:flow.in 输出文件:flow.out 简单对比时间限制:1 s 内存限制:128 MB 在一个遥远的国度,一侧是风景秀 ...
- NOIP2010 引水入城
4引水入城 题目描述 在一个遥远的国度,一侧是风景秀美的湖泊,另一侧则是漫无边际的沙漠.该国的行政区划十分特殊,刚好构成一个N 行M 列的矩形,如上图所示,其中每个格子都代表一座城市,每座城市都有一个 ...
- NOIP2010引水入城[BFS DFS 贪心]
题目描述 在一个遥远的国度,一侧是风景秀美的湖泊,另一侧则是漫无边际的沙漠.该国的行政区划十分特殊,刚好构成一个N 行M 列的矩形,如上图所示,其中每个格子都代表一座城市,每座城市都有一个海拔高度. ...
- NOIP2010 引水入城 题解
http://www.rqnoj.cn/problem/601 今天发现最小区间覆盖竟然是贪心,不用DP!于是我又找到这题出来撸了一发. 要找到最上面每个城市分别能覆盖最下面哪些城市,如果最下面有城市 ...
- noip2010 引水入城 bfs+贪心
如果能够实现,每个河边的城市对应的控制区域一定是一条线段. 所以直接bfs每个河边的城市,贪心线段的右端点 #include<cstdio> #include<cstring> ...
- Luogu1514 NOIP2010 引水入城 BFS、贪心
传送门 NOIP的题目都难以写精简题意 考虑最上面一排的某一个点对最下面一排的影响是什么样的,不难发现必须要是一段连续区间才能够符合题意. 如果不是一段连续区间,意味着中间某一段没有被覆盖的部分比周围 ...
- luogu1514 [NOIp2010]引水入城 (bfs+记忆化搜索)
我们先bfs一下看看是否能到最底下的所有点 如果不能的话,直接把不能到的那几个数一数就行了 如果能的话: 可以发现(并不可以)某格能到达的最底下的格子一定是一个连续的区间 (因为如果不连续的话,我们先 ...
- [NOIP2010] 引水入城 贪心 + 记忆化搜索
---题面--- 题解: 本蒟蒻并没有想到bfs的做法,,,, 只会dfs了 首先我们需要知道一个性质. 我们设k[i].l 为在i点建立水库可以支援到的最左边的城市,k[i].r为最右边的. 那么点 ...
- 洛谷 1514 (NOIp2010) 引水入城
题目:https://www.luogu.org/problemnew/show/P1514 如果有解,一个第一行的格子能覆盖第n行的一定是一个连续的区间. 因为如果不连续,则有围住了一些第n行的格子 ...
- NOIP2010 引水入城 贪心+DFS
我们先把简单的不能搞死,具题意可证:每个蓄水长的管辖区域一定是连续的.证明:既然我们已经能了那么我们就可以说如果这个区间不是连续的那我们取出这个区间中间阻隔开的那一段,那么对于这一整个区间来说水源不可 ...
随机推荐
- [转]Android系统Surface机制的SurfaceFlinger服务简要介绍和学习计划
转自:Android系统Surface机制的SurfaceFlinger服务简要介绍和学习计划 前面我们从Android应用程序与SurfaceFlinger服务的关系出发,从侧面简单学习了Surfa ...
- SWPFILE实现(增加swap空间)
1.mkdir /var/swap chmod 700 /var/swap(可以不用设置) 2.dd if=/dev/zero of=/var/swap/file bs=1024 count=65 ...
- IOS中nil/Nil/NULL的区别
类与对象的概念 类是对同一类事物高度的抽象,类中定义了这一类对象所应具有的静态属性(属性)和动态属性(方法). 对象是类的一个实例,是一个具体的事物. 类与对象是抽象与具体的关系. 类其实就是一种数据 ...
- C#基础--面向过程计算器
//面向过程计算器 //思路: 需要注意的是: 两个数相除 除数不能为0: //1.提示用户输入 //2.进行运算 //3.得到结果 Console.WriteLine("请输入第一个数字: ...
- 程序员是怎么炼成的---OC题集--练习答案与题目(1)
一. 1. 定义3个类,全部代码.效果:能默写,关键词全部正确. 2. ⾯面向对象和⾯面向过程有什么区别? 答:面向对象以事物(对象)为核⼼,完成事件只是一个任务.面向过程以事件为核心,为了完成任务, ...
- html5in24hours
http://www.html5in24hours.com/books/the-book/code/ 1.浏览器测试 http://browsershots.org/ 2.http://www.fon ...
- Supermarket_贪心
Description A supermarket has a set Prod of products on sale. It earns a profit px for each product ...
- 常见的XMLHttpRequest.status状态码
XMLHttpRequest.status状态码 1xx-信息提示 这些状态代码表示临时的响应.客户端在收到常规响应之前,应准备接收一个或多个1xx响应. 100-继续. 101-切换协议. 2xx- ...
- mark资料-selenium断言的分类
操作(action).辅助(accessors)和断言(assertion): 操作action: 模拟用户与 Web 应用程序的交互. 辅助accessors: 这是辅助工具.用于检查应用程序的状态 ...
- 文件IO操作
前言 本文介绍使用java进行简单的文件IO操作. 操作步骤 - 读文件 1. 定义一个Scanner对象 2. 调用该对象的input函数族进行文件读取 (参见下面代码) 3. 关闭输入流 说明:其 ...