4200: [Noi2015]小园丁与老司机
Time Limit: 20 Sec
Memory Limit: 512 MBSec
Special Judge
Submit: 139
Solved: 80
[ Submit][ Status][ Discuss]
Description
小园丁 Mr. S 负责看管一片田野,田野可以看作一个二维平面。田野上有 nn 棵许愿树,编号 1,2,3,…,n1,2,3,…,n,每棵树可以看作平面上的一个点,其中第 ii 棵树 (1≤i≤n1≤i≤n) 位于坐标 (xi,yi)(xi,yi)。任意两棵树的坐标均不相同。
老司机 Mr. P 从原点 (0,0)(0,0) 驾车出发,进行若干轮行动。每一轮,Mr. P 首先选择任意一个满足以下条件的方向:
为左、右、上、左上 45∘45∘ 、右上 45∘45∘ 五个方向之一。
沿此方向前进可以到达一棵他尚未许愿过的树。
完成选择后,Mr. P 沿该方向直线前进,必须到达该方向上距离最近的尚未许愿的树,在树下许愿并继续下一轮行动。如果没有满足条件的方向可供选择,则停止行动。他会采取最优策略,在尽可能多的树下许愿。若最优策略不唯一,可以选择任意一种。
不幸的是,小园丁 Mr. S 发现由于田野土质松软,老司机 Mr. P 的小汽车在每轮行进过程中,都会在田野上留下一条车辙印,一条车辙印可看作以两棵树(或原点和一棵树)为端点的一条线段。
在 Mr. P 之后,还有很多许愿者计划驾车来田野许愿,这些许愿者都会像 Mr. P 一样任选一种最优策略行动。Mr. S 认为非左右方向(即上、左上 45∘45∘ 、右上 45∘45∘ 三个方向)的车辙印很不美观,为了维护田野的形象,他打算租用一些轧路机,在这群许愿者到来之前夯实所有“可能留下非左右方向车辙印”的地面。
“可能留下非左右方向车辙印”的地面应当是田野上的若干条线段,其中每条线段都包含在某一种最优策略的行进路线中。每台轧路机都采取满足以下三个条件的工作模式:
从原点或任意一棵树出发。
只能向上、左上 45∘45∘ 、右上 45∘45∘ 三个方向之一移动,并且只能在树下改变方向或停止。
只能经过“可能留下非左右方向车辙印”的地面,但是同一块地面可以被多台轧路机经过。
现在 Mr. P 和 Mr. S 分别向你提出了一个问题:
请给 Mr .P 指出任意一条最优路线。
请告诉 Mr. S 最少需要租用多少台轧路机。
Input
输入文件的第 1 行包含 1 个正整数 n,表示许愿树的数量。
接下来 n 行,第 i+1 行包含 2个整数 xi,yi,中间用单个空格隔开,表示第 i 棵许愿树的坐标。
Output
输出文件包括 3 行。
输出文件的第 1 行输出 1 个整数 m,表示 Mr. P 最多能在多少棵树下许愿。
输出文件的第 2 行输出 m 个整数,相邻整数之间用单个空格隔开,表示 Mr. P 应该依次在哪些树下许愿。
输出文件的第 3 行输出 1 个整数,表示 Mr. S 最少需要租用多少台轧路机。
Sample Input
6
-1 1
1 1
-2 2
0 8
0 9
0 10
Sample Output
3
2 1 3
3
explanation
最优路线 2 条可许愿 3 次:(0,0)→(1,1)→(−1,1)→(−2,2)(0,0)→(1,1)→(−1,1)→(−2,2) 或 (0,0)→(0,8)→(0,9)→(0,10)(0,0)→(0,8)→(0,9)→(0,10)。 至少 3 台轧路机,路线是 (0,0)→(1,1)(0,0)→(1,1),(−1,1)→(−2,2)(−1,1)→(−2,2) 和 (0,0)→(0,8)→(0,9)→(0,10)(0,0)→(0,8)→(0,9)→(0,10)。
HINT
Source
[ Submit][ Status][ Discuss]
dp + 有上下界的最小流,细节非常非常非常多。。。。。搞了整整一上午。。。
先考虑前两问,,老司机的开车方向只能向纵坐标增大,或者是左右开,因而可以分开dp
定义g[i]:第i个点,由y小于yi的点转移而来,最大值
那么对于每个i,从下往上走到i的方向只有三个,找出这三个方向上距离i最近的点,直接转移就行了
定义f[i]:第i个点,由左边或者右边开过来的最大值
对于f[i]的转移,首先让所有可能的路径开到当前这一层,也就是处理好该层所有的g[i]
贪心地想,如果要从同层的i开到j,假设i在j左边,那么最好的方案,就是i先开到最左端,然后慢慢往右开
反过来也是一样的,因此对于每层的f[i],从左往右从右往左分别用g[i]更新一次就行了
因而对于g[i]的转移,其实是要同时考虑三个方向上的点的f[i]和g[i]
最后检查一下所有点的f[i],g[i],就能得出第一问了。
现在要找出路径,任取一个合法的终点,每次判断它是属于哪一类(同层转移或者下层往上得到)
然后在符合的转移集合直接枚举上一个点,再继续搜索,要注意同层转移的时候把中间点加入
这样就解决了前两问,对于第三问,建模如下
倒着dp一次,和找路径的方式一样,处理出所有可能成为最短路径上的边,同层边忽略
对于从下往上的边(i,j),从i向j连一条下界为1,上界为INF的边
对于所有可能在最短路上的点,从s到它连一条INF的边,它到t连一条INF的边
也就是说,可以无限从这个点进入,无限在这个点停止
对于该网络的最小可行流就是第三问的答案
怎么求最小流?在网上搜了很久很久,,确定了时间复杂度低又好实现的模板
先构造成循环流,但先不添加(t,s,INF)这条边
然后跑一遍超级源汇最大流,再添加(t,s,INF),跑第二遍超级源汇最大流,这次跑出的最大流就是原图最小流了
最后,,此题细节很多。。
网上看到有人实现的时候,说题目给定每层的点不超过1k,因而每层直接O(N^2)暴力找路
然后又说只T第7个点。其实第7个点根本没有每层不超过1k点的限制的
因此,我处理的时候,是开一个vis数组,判断哪些点有没有被加入最短路集合
这样dp就可以写成BFS的模式,但是不能同时找随机路径(因为路径的点可能在入集合前就被经过了)
总之码农题都是好麻烦的。。。。
#include
#include
#include
#include
#include
#include
#include
#include