P3645 [APIO2015] 雅加达的摩天楼 题解

题目说,只要一栋楼里面的一只doge知道了消息,那么他就可以在不产生任何代价的情况下将这条消息传递给这栋楼里面的所有doge。

利用这一条信息,我们可以将doge的行动转化为摩天楼之间的边,一只doge能够前往的两栋楼之间会直接或间接联通。

于是我们就可以想到跑最短路。图上的所有边权均为1,从0到1的最短路即为传递消息的代价。

然后再看数据范围:

N\[1,30000\],M\[2,30000\],Pi\[1,30000\]

当头一棒。

我们可怜的最短路算法承受不起如此多的边(O(n2) 级别),我们甚至可以将这张图看做一张完全图来计算时间复杂度,而结果必然是爆炸。

我们如果一开始分析错误了,把它当做费用流来跑SPFA的话,最多能拿到36分(UOJ&LibreOJ)/75分(Luogu)。

我们如果使用链式前向星连边、建边,跑Dijkstra的话,可以拿到36分(UOJ&LibreOJ)/80分(Luogu)的好成绩。

然后我们会发现上面会MLE,于是选用vector存边。
我们如果使用vector连边、建边,跑Dijkstra的话,可以拿到和上面一样的好成绩,并且仍然MLE。

然后我们考虑换个连边方式,不在让每一条边的边权都是相同的了,考虑从一栋楼向其他的楼连边,边权为跳跃次数,妄图减少内存用量。

结果仍为失败。

我们不再考虑显式连边,而考虑在转移的时候再连边,这里就需要用SPFA了。

然后再跑一遍就可以过了。

#include <bits/stdc++.h> #define ll long long using namespace std; const int N = 30010; int n, m; vector<int>e[N]; int dis[N], vis[N]; queue<int>q; void spfa(int s) { memset(dis, 63, sizeof(dis)); dis[s] = 0, vis[s] = 1; q.push(s); while(!q.empty()) { int u = q.front(); q.pop(); vis[u] = 0; for(auto i : e[u]) { for(int j = 1; u + i * j < n; j++) { int v = u + i * j; if(dis[v] > dis[u] + j) { dis[v] = dis[u] + j; if(!vis[v]) { q.push(v); vis[v] = 1; } } } for(int j = 1; u - i * j >= 0; j++) { int v = u - i * j; if(dis[v] > dis[u] + j) { dis[v] = dis[u] + j; if(!vis[v]) { q.push(v); vis[v] = 1; } } } } } } int main() { scanf("%d%d", &n, &m); int s, t; for(int i = 0; i < m; i++) { int a, b; scanf("%d%d", &a, &b); if(i == 0)s = a; if(i == 1) { t = a; continue; } e[a].push_back(b); } spfa(s); if(dis[t] == 0x3f3f3f3f)puts("-1"); else cout << dis[t] << endl; return 0; }

__EOF__

本文作者Kaiser Wilheim
本文链接https://www.cnblogs.com/kaiserwilheim/p/16481915.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   南陽劉子驥  阅读(44)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示