博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Codeforces 346D Robot Control(01BFS)
阅读量:4678 次
发布时间:2019-06-09

本文共 2482 字,大约阅读时间需要 8 分钟。

题意

有一个 \(N\) 个点, \(M\) 条边的有向图, 初始有一个机器人在 \(1\) 号点. 每个时刻, 这个机器人会随机选择一条从该点出发地边并通过.当机器人到达点 \(N\) 时, 它就会自动关闭.

然而这个机器人如果在某个时刻到达自己曾经到过的点的话, 它就会爆炸. 因此, 你决定对机器人实施一些命令, 让它在某些时候按照规定的边走, 而非随机选择.

问对机器人最少使用多少条命令可以让它安全到达点 \(N\) .

\(N, M \le 10^6\)

题解

十分巧妙的一道好题~

首先可以无视掉 “不能到达曾经到过的点” 的限制, 因为最优答案一定不会存在这种情况.

因为到达曾经到过的点,你至少要付出更多代价才能回到这个点,所以绝对不优。

然后我们就可以考虑一个 \(dp\) 了,令 \(dp_u\)\(u\) 走到 \(T\) 需要的最少命令。

那么显然有一个转移:

\[ dp_u=\min_{(u, v)} \{\min\{dp_v\}+1,\max\{dp_v\}\} \]

这个意义是很明显的,就不解释了。

这个本质上是个 \(0 / 1\) BFS 问题,用个双端队列维护就行了,\(0\) 加到队首, \(1\) 加到队尾就行了。

具体实现的时候,我们只有在第一次到达这个点的时候会更新 \(\min\{dp_v\}+1\) ,因为是 BFS 最早到的肯定是距离较小的点。

也就是队列中的点 \(dis\) 单调不下降。

然后最后一次到达这个点才会更新 \(\max\{dp_v\}\) ,同样这是 BFS 最晚到的点。

每个点我们只会访问一次,所以最后一次到达就是它入度减少到 \(0\) 的时候。

复杂度是 \(O(n + m)\) 的。

总结

对于一类图上有关 \(dp\)\(\min,\max\) 问题能考虑 BFS 队列的 \(dis\) 单调不下降的性质来转移。

代码

记得要把边反向,以及入度也要反向。

#include 
#define For(i, l, r) for(register int i = (l), i##end = (int)(r); i <= i##end; ++i)#define Fordown(i, r, l) for(register int i = (r), i##end = (int)(l); i >= i##end; --i)#define Set(a, v) memset(a, v, sizeof(a))#define Cpy(a, b) memcpy(a, b, sizeof(a))#define debug(x) cout << #x << ": " << x << endl#define DEBUG(...) fprintf(stderr, __VA_ARGS__)using namespace std;inline bool chkmin(int &a, int b) {return b < a ? a = b, 1 : 0;}inline bool chkmax(int &a, int b) {return b > a ? a = b, 1 : 0;}inline int read() { int x = 0, fh = 1; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') fh = -1; for (; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + (ch ^ 48); return x * fh;}void File() {#ifdef zjp_shadow freopen ("D.in", "r", stdin); freopen ("D.out", "w", stdout);#endif}const int N = 1e6 + 1e3;int n, m, deg[N], dp[N];vector
G[N];int S, T; bitset
vis;void Bfs() { Set(dp, -1); deque
Q; Q.push_front(T); dp[T] = 0; while (!Q.empty()) { int u = Q.front(); Q.pop_front(); if (u == S) return ; if (vis[u]) continue ; vis[u] = true; for (int v : G[u]) if (!-- deg[v]) { if (!~dp[v] || dp[u] < dp[v]) dp[v] = dp[u], Q.push_front(v); } else if (!~dp[v]) dp[v] = dp[u] + 1, Q.push_back(v); }}int main () { File(); n = read(); m = read(); For (i, 1, m) { int u = read(), v = read(); G[v].push_back(u); ++ deg[u]; } S = read(), T = read(); Bfs(); printf ("%d\n", dp[S]); return 0;}

转载于:https://www.cnblogs.com/zjp-shadow/p/9562888.html

你可能感兴趣的文章
万能数据库查询分析器中文版本《DB查询分析器》几年来在“中关村在线”首次大榜小榜都能够榜上有名...
查看>>
孔明灯-噪点插画
查看>>
类与接口(三)java中的接口与嵌套接口
查看>>
VS关闭Browser Link
查看>>
【题解】山头狙击战
查看>>
USB小白学习之路(3) 通过自定义请求存取外部RAM
查看>>
Solr:通过solr admin对索引库维护<四>
查看>>
mysql写注释的几种方法
查看>>
UPC-2243 军事情报【递推】
查看>>
HTML常用标签查询
查看>>
四方精创前端开发面试经验
查看>>
软件测试作业(一)
查看>>
使用icomoon把svg图片生成字体图标
查看>>
C++中 使用数组作为map容器VAlue值的解决方法
查看>>
mysql left join,right join,inner join用法分析
查看>>
Ewebeditor最新漏洞及漏洞大全
查看>>
java中synchronized使用方法
查看>>
hdu - 3049 - Data Processing(乘法逆元)
查看>>
冷门却使用的 javascript 技巧
查看>>
C++ 类之间的互相调用
查看>>