题目:

洛谷 2304

LOJ 2134

(LOJ 上每个测试点有部分分)

写了快一天 …… 好菜啊

分析:

毒瘤二合一题 ……

注意本题(及本文)使用 \(x\) 向右,\(y\) 向上的「数学坐标系」,而不是 \(x\) 向下,\(y\) 向右的所谓「OI 坐标系」。「同一行」指 \(y\) 相同,「同一列」指 \(x\) 相同。

老司机

注意,只能在 没有经过的 树下转向,并且每棵树只能访问一次。

第一反应是 \(f_{u}\) 表示从点 \(u\) (树 \(u\) )出发能走到的最多的点数(不含本身),记忆化搜索,则答案就是 \(f_0\) (令 \((0,0)\) 为 \(0\) 号点)。然而,这样转移是有环的,因为同一行中互相可达。

那么就考虑逐行转移。先对于所有点 \(u\) 处理出所有不同行的可达的 \(v\) (即 \(u\) 与 \(v\) 的横坐标相等、横纵坐标之和相等或横纵坐标之差相等且 \(u\) 与 \(v\) 的连线上没有其他点)。计算 \(f(u)\) 时,先枚举它在同行走到了哪个点,再枚举它从那个点走到了上方的哪个点。设当前点是该行的第 \(p\) 个点,要走到同行的第 \(k\) 个点。若 \(p<k\) ,则最优策略是先走完左侧的所有点,再向右走到 \(k\) ,然后向上走;若 \(p=k\) ,则只能直接向上走;若 \(p>k\) ,则先走完右侧的所有点,再向左走到 \(k\) 。形式化地(其中 \(p_{i,j}\) 表示 \(y=i\) 的横坐标从小到大第 \(j\) 个点,标号从 \(0\) 开始。\(a_i\) 表示 \(y=i\) 的总点数):

\[f_{p_{y,i}}=\max\begin{cases}
a_y-k-1\ (k<i且p_{y,k}无出边)\\
f_v+a_y-k\ (k<i且p_{y,k}到v有连边)\\
f_v+1\ (p_{y,i}到v有连边)\\
k\ (k>i且p_{y,k}无出边)\\
f_v+k+1\ (k>i且p_{y,i}到v有连边)\\
\end{cases}
\]

(注意要讨论边界情况。状态定义中不含 \(p_{y,i}\) 这点本身的贡献)

时间复杂度 \(O(nm)\) ,其中 \(m\) 表示每行最大的点数。题面上说 \(m\leq 1000\) 但是小恐龙说数据里有到 \(1600\) 多的?

至于输出方案,转移的时候记录一下转移时用的 \(k\) 是哪个,然后在 \(p_{y,k}\) 的出边中找哪个点的 \(f\) 值加上 \(a_y-k-1\) 之类的东西(视 \(k\) 和 \(i\) 的大小关系而定)等于当前点的 \(f\) 值,走过去就 OK 啦。

于是第一问就 愉快地 解决啦。

小园丁

首先用和输出方案类似的方法处理出哪些连边是可能存在于最优路径中的。然后考虑限制:

压路机可以从任意一棵树下出发,在任意一棵树下停止

压路机只能经过可能存在于最优路径中的边,每条边要被经过至少一次\

这不是 …… 网络流??

每条边的权值是 \([1,+\infty)\) ,然后源点向所有点连 \([0,+\infty)\) ,所有点向汇点连 \([0,+\infty)\) ,然后就是一个上下界有源汇最小流板子了。(啥玩意?) 我是照着小恐龙的博客现学的。

为酒肉朋友打广告:有上下界的网络流/费用流 学习笔记 - Little Dino

代码:

写自闭了 ……

  1. #include <cstdio>
  2. #include <algorithm>
  3. #include <cstring>
  4. #include <cctype>
  5. #include <vector>
  6. #include <map>
  7. #include <queue>
  8. using namespace std;
  9. namespace zyt
  10. {
  11. template<typename T>
  12. inline bool read(T &x)
  13. {
  14. char c;
  15. bool f = false;
  16. x = 0;
  17. do
  18. c = getchar();
  19. while (c != EOF && c != '-' && !isdigit(c));
  20. if (c == EOF)
  21. return false;
  22. if (c == '-')
  23. f = true, c = getchar();
  24. do
  25. x = x * 10 + c - '0', c = getchar();
  26. while (isdigit(c));
  27. if (f)
  28. x = -x;
  29. return true;
  30. }
  31. template<typename T>
  32. inline void write(T x)
  33. {
  34. static char buf[20];
  35. char *pos = buf;
  36. if (x < 0)
  37. putchar('-'), x = -x;
  38. do
  39. *pos++ = x % 10 + '0';
  40. while (x /= 10);
  41. while (pos > buf)
  42. putchar(*--pos);
  43. }
  44. typedef pair<int, int> pii;
  45. const int N = 5e4 + 10, M = 1e3 + 10, INF = 0x3f3f3f3f;
  46. int n, X[N], Y[N], head[N], ecnt, ycnt;
  47. pii pos[N], dp[N];
  48. bool vis[N];
  49. vector<int> id[N];
  50. map<int, vector<int> > mp;
  51. struct edge
  52. {
  53. int to, next;
  54. }e[N * 3];
  55. void add(const int a, const int b)
  56. {
  57. e[ecnt] = (edge){b, head[a]}, head[a] = ecnt++;
  58. }
  59. bool cmpx(const int a, const int b)
  60. {
  61. return X[a] < X[b];
  62. }
  63. void init()
  64. {
  65. static map<int, int> x, x_add_y, x_sub_y;
  66. memset(head, -1, sizeof(int[n + 1]));
  67. for (int i = 1; i <= n; i++)
  68. mp[Y[i]].push_back(i);
  69. for (auto it = mp.rbegin(); it != mp.rend(); it++)
  70. {
  71. sort(it->second.begin(), it->second.end(), cmpx);
  72. id[++ycnt] = it->second;
  73. for (auto itt = it->second.begin(); itt != it->second.end(); itt++)
  74. {
  75. int u = *itt;
  76. pos[u] = pii(ycnt, itt - it->second.begin());
  77. if (x.count(X[u]))
  78. add(u, x[X[u]]);
  79. x[X[u]] = u;
  80. if (x_add_y.count(X[u] + Y[u]))
  81. add(u, x_add_y[X[u] + Y[u]]);
  82. x_add_y[X[u] + Y[u]] = u;
  83. if (x_sub_y.count(X[u] - Y[u]))
  84. add(u, x_sub_y[X[u] - Y[u]]);
  85. x_sub_y[X[u] - Y[u]] = u;
  86. }
  87. }
  88. }
  89. template<typename T>
  90. inline void get_max(T &a, const T b)
  91. {
  92. a = max(a, b);
  93. }
  94. int dfs(const int u)
  95. {
  96. int y = pos[u].first, p = pos[u].second;
  97. if (vis[u])
  98. return dp[u].first;
  99. vis[u] = true;
  100. dp[u] = pii(0, 0);
  101. for (int k = 0; k < p; k++)
  102. {
  103. int now = id[y][k], res = 0;
  104. for (int i = head[now]; ~i; i = e[i].next)
  105. {
  106. int v = e[i].to;
  107. get_max(res, dfs(v));
  108. }
  109. get_max(dp[u], pii(res + id[y].size() - k - (head[now] == -1), now));
  110. }
  111. for (int i = head[u]; ~i; i = e[i].next)
  112. {
  113. int v = e[i].to;
  114. get_max(dp[u], pii(dfs(v) + 1, u));
  115. }
  116. for (int k = p + 1; k < id[y].size(); k++)
  117. {
  118. int now = id[y][k], res = 0;
  119. for (int i = head[now]; ~i; i = e[i].next)
  120. {
  121. int v = e[i].to;
  122. get_max(res, dfs(v));
  123. }
  124. get_max(dp[u], pii(res + k + (head[now] != -1), now));
  125. }
  126. return dp[u].first;
  127. }
  128. void work1()
  129. {
  130. int ans = dfs(n);
  131. write(ans), putchar('\n');
  132. int tmp = n;
  133. while (tmp)
  134. {
  135. if (tmp != n)
  136. write(tmp), putchar(' ');
  137. int y = pos[tmp].first, p = pos[tmp].second, nxt = dp[tmp].second, delta = 1, nxtt = 0;
  138. if (!nxt)
  139. break;
  140. if (pos[nxt].second < p)
  141. {
  142. for (int i = p + 1; i < id[y].size(); i++)
  143. write(id[y][i]), putchar(' '), ++delta;
  144. for (int i = p - 1; i >= pos[nxt].second; i--)
  145. write(id[y][i]), putchar(' '), ++delta;
  146. }
  147. else if (pos[nxt].second > p)
  148. {
  149. for (int i = p - 1; i >= 0; i--)
  150. write(id[y][i]), putchar(' '), ++delta;
  151. for (int i = p + 1; i <= pos[nxt].second; i++)
  152. write(id[y][i]), putchar(' '), ++delta;
  153. }
  154. for (int i = head[nxt]; ~i; i = e[i].next)
  155. {
  156. int v = e[i].to;
  157. if (dp[v].first + delta == dp[tmp].first)
  158. {
  159. nxtt = v;
  160. break;
  161. }
  162. }
  163. tmp = nxtt;
  164. }
  165. putchar('\n');
  166. }
  167. namespace Subtask2
  168. {
  169. int s, t, S, T, out[N];
  170. namespace Dinic
  171. {
  172. struct edge
  173. {
  174. int to, w, next;
  175. }e[N * 12];
  176. int cur[N], dis[N], head[N], ecnt, s, t;
  177. void add(const int a, const int b, const int c)
  178. {
  179. e[ecnt] = (edge){b, c, head[a]}, head[a] = ecnt++;
  180. }
  181. void addtw(const int a, const int b, const int c)
  182. {
  183. add(a, b, c), add(b, a, 0);
  184. }
  185. bool bfs()
  186. {
  187. memset(dis, -1, sizeof(int[T + 1]));
  188. memcpy(cur, head, sizeof(int[T + 1]));
  189. static queue<int> q;
  190. q.push(s);
  191. dis[s] = 0;
  192. while (!q.empty())
  193. {
  194. int u = q.front();
  195. q.pop();
  196. for (int i = head[u]; ~i; i = e[i].next)
  197. {
  198. int v = e[i].to;
  199. if (e[i].w && dis[v] == -1)
  200. dis[v] = dis[u] + 1, q.push(v);
  201. }
  202. }
  203. return dis[t] != -1;
  204. }
  205. int dfs(const int u, const int minn)
  206. {
  207. if (u == t || !minn)
  208. return minn;
  209. int used = 0;
  210. for (int &i = cur[u]; ~i; i = e[i].next)
  211. {
  212. int v = e[i].to;
  213. if (e[i].w && dis[v] == dis[u] + 1)
  214. {
  215. int w = dfs(v, min(minn - used, e[i].w));
  216. e[i].w -= w, e[i ^ 1].w += w, used += w;
  217. if (used == minn)
  218. break;
  219. }
  220. }
  221. return used;
  222. }
  223. int work(const int _s, const int _t)
  224. {
  225. s = _s, t = _t;
  226. int ans = 0;
  227. while (bfs())
  228. ans += dfs(s, INF);
  229. return ans;
  230. }
  231. }
  232. void work()
  233. {
  234. using Dinic::addtw;
  235. static queue<int> q;
  236. static bool vis[N], mark[N * 3];
  237. s = n + 1, t = n + 2, S = n + 3, T = n + 4;
  238. memset(Dinic::head, -1, sizeof(int[T + 1]));
  239. for (int i = 1; i <= n; i++)
  240. addtw(s, i, INF), addtw(i, t, INF);
  241. q.push(n);
  242. while (!q.empty())
  243. {
  244. int u = q.front();
  245. int y = pos[u].first, p = pos[u].second;
  246. q.pop();
  247. for (int k = 0; k < p; k++)
  248. {
  249. int now = id[y][k], delta = id[y].size() - k;
  250. for (int i = head[now]; ~i; i = e[i].next)
  251. {
  252. int v = e[i].to;
  253. if (!mark[i] && dp[v].first + delta == dp[u].first)
  254. {
  255. ++out[now], --out[v], addtw(now, v, INF), mark[i] = true;
  256. if (!vis[v])
  257. q.push(v), vis[v] = true;
  258. }
  259. }
  260. }
  261. for (int i = head[u]; ~i; i = e[i].next)
  262. {
  263. int v = e[i].to;
  264. if (!mark[i] && dp[v].first + 1 == dp[u].first)
  265. {
  266. ++out[u], --out[v], addtw(u, v, INF), mark[i] = true;
  267. if (!vis[v])
  268. q.push(v), vis[v] = true;
  269. }
  270. }
  271. for (int k = p + 1; k < id[y].size(); k++)
  272. {
  273. int now = id[y][k], delta = k + 1;
  274. for (int i = head[now]; ~i; i = e[i].next)
  275. {
  276. int v = e[i].to;
  277. if (!mark[i] && dp[v].first + delta == dp[u].first)
  278. {
  279. ++out[now], --out[v], addtw(now, v, INF), mark[i] = true;
  280. if (!vis[v])
  281. q.push(v), vis[v] = true;
  282. }
  283. }
  284. }
  285. }
  286. for (int i = 1; i <= n; i++)
  287. if (out[i] < 0)
  288. addtw(S, i, -out[i]);
  289. else
  290. addtw(i, T, out[i]);
  291. addtw(t, s, INF);
  292. Dinic::work(S, T);
  293. int flow = Dinic::e[Dinic::ecnt - 1].w;
  294. Dinic::e[Dinic::ecnt - 1].w = Dinic::e[Dinic::ecnt - 2].w = 0;
  295. write(flow - Dinic::work(t, s));
  296. }
  297. }
  298. int work()
  299. {
  300. read(n);
  301. for (int i = 1; i <= n; i++)
  302. read(X[i]), read(Y[i]);
  303. ++n, X[n] = Y[n] = 0;
  304. init();
  305. work1();
  306. Subtask2::work();
  307. return 0;
  308. }
  309. }
  310. int main()
  311. {
  312. #ifdef BlueSpirit
  313. freopen("2304.in", "r", stdin);
  314. #endif
  315. return zyt::work();
  316. }

【洛谷2304_LOJ2134】[NOI2015]小园丁与老司机(动态规划_网络流)的更多相关文章

  1. uoj132/BZOJ4200/洛谷P2304 [Noi2015]小园丁与老司机 【dp + 带上下界网络流】

    题目链接 uoj132 题解 真是一道大码题,,,肝了一个上午 老司机的部分是一个\(dp\),观察点是按\(y\)分层的,而且按每层点的上限来看可以使用\(O(nd)\)的\(dp\),其中\(d\ ...

  2. [UOJ#132][BZOJ4200][luogu_P2304][NOI2015]小园丁与老司机

    [UOJ#132][BZOJ4200][luogu_P2304][NOI2015]小园丁与老司机 试题描述 小园丁 Mr. S 负责看管一片田野,田野可以看作一个二维平面.田野上有 \(n\) 棵许愿 ...

  3. [BZOJ4200][Noi2015]小园丁与老司机

    4200: [Noi2015]小园丁与老司机 Time Limit: 20 Sec  Memory Limit: 512 MBSec  Special JudgeSubmit: 106  Solved ...

  4. 【BZOJ4200】[Noi2015]小园丁与老司机 DP+最小流

    [BZOJ2839][Noi2015]小园丁与老司机 Description 小园丁 Mr. S 负责看管一片田野,田野可以看作一个二维平面.田野上有 nn 棵许愿树,编号 1,2,3,…,n1,2, ...

  5. luogu P2304 [NOI2015]小园丁与老司机 dp 上下界网络流

    LINK:小园丁与老司机 苦心人 天不负 卧薪尝胆 三千越甲可吞吴 AC的刹那 真的是泪目啊 很久以前就写了 当时记得特别清楚 写到肚子疼.. 调到胳膊疼.. ex到根不不想看的程度. 当时wa了 一 ...

  6. BZOJ4200 & 洛谷2304 & UOJ132:[NOI2015]小园丁与老司机——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=4200 https://www.luogu.org/problemnew/show/P2304 ht ...

  7. [BZOJ]4200: [Noi2015]小园丁与老司机

    Time Limit: 20 Sec  Memory Limit: 512 MBSec  Special Judge Description 小园丁 Mr. S 负责看管一片田野,田野可以看作一个二维 ...

  8. [Noi2015]小园丁和老司机

    来自FallDream的博客,未经允许,请勿转载,谢谢. 小园丁 Mr. S 负责看管一片田野,田野可以看作一个二维平面.田野上有n棵许愿树,编号1,2,3,…,n,每棵树可以看作平面上的一个点,其中 ...

  9. 【bzoj4200】[Noi2015]小园丁与老司机 STL-map+dp+有上下界最小流

    题目描述 小园丁 Mr. S 负责看管一片田野,田野可以看作一个二维平面.田野上有 nn 棵许愿树,编号 1,2,3,…,n1,2,3,…,n,每棵树可以看作平面上的一个点,其中第 ii 棵树 (1≤ ...

随机推荐

  1. Nexus3.0.1如何上传第三方插件

    原文:http://blog.csdn.net/wang465745776/article/details/52527905 前提条件 Nexus 3.0.1 提出问题 如何上传第三方插件到Nexus ...

  2. Spring MVC 异步处理请求,提高程序性能

    原文:http://blog.csdn.net/he90227/article/details/52262163 什么是异步模式 如何在Spring MVC中使用异步提高性能? 一个普通 Servle ...

  3. 白话空间统计之四:P值和Z值(上):零如果

    本来今天想要讲讲软件操作的,后来发现好像还有好几个重要的指标没有说,干脆等所有说完在讲操作吧.否则操作出来的结果会发现大量的"不明觉厉". 首先是空间统计里面非常神奇的两个值:P值 ...

  4. (void __user *)arg 中__user的作用

    __user宏简单告诉编译器(通过 noderef)不应该解除这个指针的引用(因为在当前地址空间中它是没有意义的). (void __user *)arg 指的是arg值是一个用户空间的地址,不能直接 ...

  5. Selenium系列之--01 简介【转】

    1.selenium 工具组件 1.1 selenium2,也称为selenium webdriver.webdriver原来是另一个自动化测试工具,后与selenium 合并了.webdriver直 ...

  6. C++语言笔记系列之二十——模版

    1.随意输入两个数x和y,输出最大值max. int max(int x, int y) {return x>y? x:y;} 2.函数模版 (1)用一种或者多种通用类型去表示函数--函数模版. ...

  7. 嵌入式开发之davinci--- 8148 中dsp在dsp_drv.c中的processdata()加算法出现下边缘条纹问题

    (1)问题原因 dsp在alglink_priv.c中做灰度处理发现,下面出现条纹,后面发现是cache 缓存没及时写进内存问题 (2)解决办法 for(frameId=0; frameId<f ...

  8. Interpret bytes as packed binary data

    7.1. struct — Interpret bytes as packed binary data — Python 3.6.5 documentation https://docs.python ...

  9. 内存溢出-jvisualvm排查问题

    先来一段能够内存溢出的程序 public static void main(String[] args) { List<Object> list = new ArrayList<&g ...

  10. 安装APK报错解决方法【转】

    本文转载自:http://blog.csdn.net/zy1235678/article/details/38122827 adb install xxx.apk 报错,安装APK报错:INSTALL ...