[NOIP2010] 引水入城 贪心 + 记忆化搜索
题解:
本蒟蒻并没有想到bfs的做法,,,,
只会dfs了
首先我们需要知道一个性质。
我们设k[i].l 为在i点建立水库可以支援到的最左边的城市,k[i].r为最右边的。
那么点i可以支援到的城市必然有且仅有k[i].l ~ k[i].r这整个区间。
这是为什么呢?
其实我也不会证明,但是可以大致说明一下,也不知道是否严谨。。。。

观察上图我们可以发现,假设我们可以到达 l 和 r ,却无法到达中间那个,那么说明mid要高于 l 和 r,
通过观察我随意画的几组路线可以发现,如果mid无法通过上方到达,但我们显然是有机会去上方的,而我们没有去。这说明上面也堵住了!
那么这说明什么?
说明mid根本无法到达啊。
所以我们在dfs找 l 和 r 的时候,直接记录哪些城市是已经到达的,dfs完后扫一遍,看是否有城市无法到达,如果有,那么说明我们找到的 l 和 r 是不对的,同时说明任务无法完成,于是按题意输出即可
否则就贪心的做线段覆盖。
同时注意dfs需要记忆化(也相当于DP了)
先把区间按照 l 为第一优先级,r为第二优先级排序,然后在l可以触碰到当前位置的时候,优先选择r靠后的。
这个的正确性是显然的。
因此我们就可以得到答案了
代码中我懒得想,所以用暴力处理了一下n = 1的情况。。。。
#include<bits/stdc++.h>
using namespace std;
#define R register int
#define AC 510
#define inf 10000000
#define getchar() *o++
#define D printf("line in %d\n", __LINE__);
char READ[], *o = READ;
int n, m, tot;
int s[AC][AC], a[] = {, , -, }, b[] = {-, , , };
bool z[AC * AC], vis[AC]; struct node{
int l, r;
}k[AC * AC]; inline int read()
{
int x = ; char c = getchar();
while(c > '' || c < '') c = getchar();
while(c >= '' && c <= '') x = x * + c - '', c = getchar();
return x;
} void pre()
{
n = read(), m = read();
for(R i = ; i <= n; i++)
for(R j = ; j <= m; j++) s[i][j] = read();
} inline int get(int x, int y)
{
return (x - ) * m + y;
} node dfs(int x, int y)
{
int _x, _y, id;node tmp, now;
id = get(x, y);
if(z[id]) return k[id];
tmp.l = inf, tmp.r = ;
if(x == n)
{
vis[y] = true;
tmp.l = tmp.r = y;
}
z[id] = true;
for(R i = ; i <= ; i++)
{
_x = x + a[i], _y = y + b[i];
if(s[_x][_y] >= s[x][y]) continue;
if(_x > && _x <= n && _y > && _y <= m)
{
now = dfs(_x, _y);
if(now.l < tmp.l) tmp.l = now.l;
if(now.r > tmp.r) tmp.r = now.r;
}
}
k[id] = tmp;
return tmp;
} inline bool cmp(node a, node b)
{
if(a.l != b.l) return a.l < b.l;
else return a.r < b.r;
} void work()
{
int tmp = ;
for(R i = ; i <= m; i++) if(!vis[i]) ++tmp;//error!!!是m啊
if(tmp)
{
printf("0\n%d\n", tmp);
exit();
}
int ans = , l = ;//记录当前使用段数 +
sort(k + , k + m + , cmp);
//for(R i = 1; i <= m; i++)//只能用第一行
int i = ;
while()
{//error 之前那样写会死循环的。。。。
//printf("%d\n", i);
tmp = ;//记录最远能到哪里
while(k[i].l <= l + && i <= m)
{
if(k[i].r > tmp) tmp = k[i].r;
++i;
}
l = tmp, ++ans;
if(l == m) break;
}
printf("1\n%d\n", ans);
} void special()//如果沙漠城市临海
{
int ans = , cnt = , tmp = , l, r;
while(tmp < m && s[][tmp + ] < s[][tmp]) ++tmp;
k[++cnt].l = , k[cnt].r = tmp;
tmp = m;
while(tmp > && s[][tmp] > s[][tmp - ]) --tmp;
k[++cnt].l = tmp, k[cnt].r = m;
for(R i = ; i < m; i++)//因为只有一行,最多就500个城市,所以暴力即可
{
if(s[][i] >= s[][i - ] && s[][i] >= s[][i + ])
{
l = r = i;
while(r < m && s[][r + ] < s[][r]) ++r;
while(l > && s[][l - ] < s[][l]) --l;
k[++cnt] = (node) {l, r};
}
}
l = ;
sort(k + , k + m + , cmp);
int i = ;
while()
{//error 之前那样写会死循环的。。。。
//printf("%d\n", i);
tmp = ;//记录最远能到哪里
while(k[i].l <= l + && i <= m)
{
if(k[i].r > tmp) tmp = k[i].r;
++i;
}
l = tmp, ++ans;
if(l == m) break;
}
printf("1\n%d\n", ans);
} int main()
{
freopen("in.in", "r", stdin);
fread(READ, , , stdin);
pre();
if(n == )
{
special();
exit();
}
for(R i = ; i <= m; i++) dfs(, i);
work();
//printf("time used ... %lf\n", (double) clock()/CLOCKS_PER_SEC);
fclose(stdin);
return ;
}
[NOIP2010] 引水入城 贪心 + 记忆化搜索的更多相关文章
- luogu1514 [NOIp2010]引水入城 (bfs+记忆化搜索)
我们先bfs一下看看是否能到最底下的所有点 如果不能的话,直接把不能到的那几个数一数就行了 如果能的话: 可以发现(并不可以)某格能到达的最底下的格子一定是一个连续的区间 (因为如果不连续的话,我们先 ...
- NOIP2010 引水入城 贪心+DFS
我们先把简单的不能搞死,具题意可证:每个蓄水长的管辖区域一定是连续的.证明:既然我们已经能了那么我们就可以说如果这个区间不是连续的那我们取出这个区间中间阻隔开的那一段,那么对于这一整个区间来说水源不可 ...
- 洛谷1514 引水入域 dp+记忆化搜索
题目链接:https://www.luogu.com.cn/problem/P1514 题意大致是:给定一个(n,m)的数值矩阵,可以在第一行建造水库,如果一个格子周围的某格子值小于它,那水就可以流到 ...
- 521. [NOIP2010] 引水入城 cogs
521. [NOIP2010] 引水入城 ★★★ 输入文件:flow.in 输出文件:flow.out 简单对比时间限制:1 s 内存限制:128 MB 在一个遥远的国度,一侧是风景秀 ...
- noip 2010 引水入城 贪心 + 搜索
不难分析出如果有解则每个蓄水厂所能覆盖到的干旱城市一定是连续的.否则,中间那些没被覆盖的部分永远都不能被覆盖到. 当然,每个蓄水厂所覆盖的城市有可能不连续,不过既然有解,则一定都是连续的.我们可以开一 ...
- Codeforces Round #536 E. Lunar New Year and Red Envelopes /// 贪心 记忆化搜索 multiset取最大项
题目大意: 给定n m k:(1≤n≤1e5, 0≤m≤200, 1≤k≤1e5) 表示n个时间长度内 最多被打扰m次 k个红包 接下来k行描述红包 s t d w:(1≤s≤t≤d≤n , 1≤w≤ ...
- Codeforces Round #554 (Div. 2) D 贪心 + 记忆化搜索
https://codeforces.com/contest/1152/problem/D 题意 给你一个n代表合法括号序列的长度一半,一颗有所有合法括号序列构成的字典树上,选择最大的边集,边集的边没 ...
- NOIP2010 引水入城
4引水入城 题目描述 在一个遥远的国度,一侧是风景秀美的湖泊,另一侧则是漫无边际的沙漠.该国的行政区划十分特殊,刚好构成一个N 行M 列的矩形,如上图所示,其中每个格子都代表一座城市,每座城市都有一个 ...
- [洛谷P1514] NOIP2010 引水入城
问题描述 在一个遥远的国度,一侧是风景秀美的湖泊,另一侧则是漫无边际的沙漠.该国的行政区划十分特殊,刚好构成一个N 行×M 列的矩形,如上图所示,其中每个格子都代表一座城市,每座城市都有一个海拔高度. ...
随机推荐
- React-精华版
现在最热门的前端框架有AngularJS.React.Bootstrap等.自从接触了ReactJS,ReactJs的虚拟DOM(Virtual DOM)和组件化的开发深深的吸引了我,下面来跟我一起领 ...
- 使用apache cgi运行ruby脚本
在ubuntu下 进入 /usr/lib/cgi-bin目录 新建文件 ruby.cgi 内容如下 #!/usr/bin/ruby print "Content-type: text/htm ...
- DSP5509的定时器实验-第2篇
1. 导入Easy5509开发板的例程EX02_TIME,5509有2个16位的定时器,有点少啊 2. 直接编译,提示找不到CSL.h,其实我也好奇,CSL库是从哪里来的?RTS库从哪里来的?头文件在 ...
- linux下实现ssh无密码登录访问
在192.168.9.51机器上 1)运行:#ssh-keygen -t rsa 2)然后拍两下回车(均选择默认) 3)运行: #ssh-copy-id -i /root/.ssh/id_rsa.pu ...
- 引领技术变革,腾讯云、腾讯WeTest和英特尔,合作布局云游戏
WeTest 导读 ChinaJoy作为中国泛娱乐产业年度风向标,受到全球业界的高度关注.在本届ChinaJoy上,腾讯云.腾讯WeTest和英特尔,合作为游戏玩家.游戏开发者等业界人士联合展出了云游 ...
- C# 简单工厂
如下: public static IList<T> Create<T>(Type type) { if (type == typeof(List<T>)) { r ...
- Siki_Unity_3-13_编程内功修炼-算法
Unity 3-13 编程内功修炼 -- 算法 任务1&2:课程介绍 主要算法: 分治法 堆排序 二叉树 动态规划 贪心算法 图 任务3:分治算法 -- Divide and Conquer ...
- lintcode 466. 链表节点计数
466. 链表节点计数 计算链表中有多少个节点. 样例 给出 1->3->5, 返回 3. /** * Definition of ListNode * class ListNode ...
- Java进阶知识点: 枚举值
Java进阶知识点1:白捡的扩展性 - 枚举值也是对象 一.背景 枚举经常被大家用来储存一组有限个数的候选常量.比如下面定义了一组常见数据库类型: public enum DatabaseType ...
- 在本地电脑使用远程服务器的图形界面——包括 MATLAB、PyCharm 等各种软件
在用本地电脑连接远程服务器的时候,大部分时候只能用命令行来操作.虽然可以 在本地电脑用 PyCharm 进行远程调试.在本地电脑远程使用服务器的 Jupyter Notebook.Ubuntu 和 W ...