题目传送门


题目描述

牛牛所在的W市是一个不太大的城市,城市有n个路口以及m条公路,这些双向连通的公路长度均为1,保证你可以从一个城市直接或者间接移动到所有的城市。牛牛在玩宝可梦Go,众所周知呢,这个游戏需要到城市的各个地方去抓宝可梦,假设现在牛牛知道了接下来将会刷出k只宝可梦,他还知道每只宝可梦的刷新时刻、地点以及该宝可梦的战斗力,如果在宝可梦刷新时,牛牛恰好在那个路口,他就一定能够抓住那只宝可梦。

由于游戏公司不想让有选择恐惧症的玩家为难,所以他们设计不存在任何一个时刻同时刷出两只及以上的宝可梦。

假设不存在任何一个时刻会同时刷出两只宝可梦,牛牛一开始在城市的1号路口,最开始的时刻为0时刻,牛牛可以在每个时刻之前移动到相邻他所在位置的路口,当然他也可以保持原地不动,他现在想知道他能够捕获的宝可梦战斗力之和最大为多少?


输入描述:

第一行输入两个正整数 n , m , ( 1 ≤ n ≤ 200 , 0 ≤ m ≤ 10000 ) n,m,(1 \leq n \leq 200,0 \leq m \leq 10000) n,m,(1≤n≤200,0≤m≤10000)表示城市的路口数目以及公路数目。

接下来m行每行两个正整数 u , v ( 1 ≤ u , v ≤ n ) u,v(1 \leq u,v \leq n) u,v(1≤u,v≤n)表示一条长度为1链接两个路的公路。

接下来一行输入一个正整数 k ( 1 ≤ k ≤ 1 0 5 ) k(1 \leq k \leq 10^5) k(1≤k≤105)表示宝可梦的数目。

接下来输入k行,每行三个正整数 t i , p i , v a l i ( 1 ≤ p i ≤ n , 1 ≤ t i , v a l i ≤ 1 0 9 ) t_i,p_i,val_i(1 \leq p_i \leq n,1 \leq t_i,val_i \leq 10^9) ti​,pi​,vali​(1≤pi​≤n,1≤ti​,vali​≤109),分别表示宝可梦刷新的时间、地点、以及战斗力,输入数据保证不会出现在同一时刻刷出多只宝可梦。


输出描述:

输出一个整数表示牛牛能捉到的宝可梦战斗力之和最大是多少。


输入

3 2
1 2
2 3
3
1 1 5
2 3 10
3 2 1

1 0
3
1 1 100
100 1 10000
10000 1 1

3 2
1 2
2 3
1
1 3 1000000000

3 2
1 2
2 3
1
1 2 1000000000


输出

11

10101

0

1000000000


备注:

输入数据保证不会出现在同一时刻刷出多只宝可梦。


题解

  • 既然要在不同的城市移动,想要尽可能捕获多的宝可梦,那么就需要走最短路: F l o y d Floyd Floyd
  • 接下来我们需要捕捉宝可梦,很显然需要按照时间升序将宝可梦排序
  • 定义 d p [ i ] : 最 后 捕 获 的 宝 可 梦 为 i 的 最 大 价 值 dp[i]:最后捕获的宝可梦为i的最大价值 dp[i]:最后捕获的宝可梦为i的最大价值
  • 然后我们考虑状态转移,可以发现,对于 当 前 宝 可 梦 所 在 点 p o s i 当前宝可梦所在点pos_i 当前宝可梦所在点posi​, 前 一 宝 可 梦 所 在 点 p o s j 前一宝可梦所在点pos_j 前一宝可梦所在点posj​,如果 两 只 宝 可 梦 刷 新 时 间 < = d i s [ p o s i ] [ p o s j ] 两只宝可梦刷新时间 <= dis[pos_i][pos_j] 两只宝可梦刷新时间<=dis[posi​][posj​],那么说明可以从 d p [ j ] dp[j] dp[j] 转移到 d p [ i ] dp[i] dp[i] ,即可以更新 d p [ i ] = d p [ j ] + v a l i dp[i]=dp[j]+val_i dp[i]=dp[j]+vali​
  • 注意题目并不保证图联通,所以初始化地图 d i s = i n f dis=inf dis=inf
  • 目前来看已经可以解决问题了,但是发现宝可梦数量 k < = 1 e 5 k<=1e5 k<=1e5,而 01背包dp过程复杂度 k 2 k^2 k2,时间复杂度肯定是不允许的。
  • 我们发现,地图点数 n < = 200 n<=200 n<=200,因此任意两点最短路最多是199(为了好看当作200即可)。

    考虑上图情况,如果 j → i j \rightarrow i j→i时间超过了200,说明我们在这段时间内,可以去到任意位置去找其他宝可梦,可以不从 j j j 直接到 i i i,那么我们知道01背包内层循环顺序是逆序的,也就是说,当我们判断 j → i j \rightarrow i j→i 的时候,我们已经经过了 k k k 点,也就是说,我们已经得到了 j → k → i j \rightarrow k \rightarrow i j→k→i 的最优解,所以并不需要再次重复计算 j → i j \rightarrow i j→i。
  • 但是我们可以直接让 Δ t > = 200 \Delta t>=200 Δt>=200 的直接跳过么,很显然不可以,因为如果 j → i > = 200 j \rightarrow i >=200 j→i>=200,但是实际上 j → i j \rightarrow i j→i 的价值更优于 j → k → i j \rightarrow k \rightarrow i j→k→i;或者没有 k k k 供我们转移,那么我们就不可以直接跳过 j j j。
  • 但其实分析到这里的话,随便怎么围绕常熟优化一下都是可以 A c c e p t Accept Accept 的,我采用的是每次找最靠近的 200 200 200 个宝可梦,这样复杂度就是 O ( 200 k ) O(200k) O(200k) 了。

AC-Code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int maxn = 2e5 + 7;int dis[201][201];void floyd(int n) {for (int k = 1; k <= n; ++k)for (int i = 1; i <= n; ++i)for (int j = 1; j <= n; ++j)dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
}struct Node {int pos, t, val;Node() {}Node(int pos, int t, int val) :pos(pos), t(t), val(val) {}
}node[maxn];ll dp[maxn];int main() {int n, m;   while (cin >> n >> m) {for (int i = 1; i <= n; ++i)for (int j = 1; j <= n; ++j)dis[i][j] = i == j ? 0 : 0x3f3f3f3f;for (int i = 0; i < m; ++i) {int u, v;    cin >> u >> v;dis[u][v] = dis[v][u] = 1;}floyd(n);int k;  cin >> k;for (int i = 1; i <= k; ++i) {cin >> node[i].t >> node[i].pos >> node[i].val;dp[i] = -1e18;}sort(node + 1, node + 1 + k, [](Node a, Node b) {return a.t < b.t; });node[0].pos = 1, node[0].t = 0; // 初始化牛牛位置dp[0] = 0;ll ans = 0;for (int i = 1; i <= k; ++i) {for (int j = i - 1; j >= 0; --j) {if (i - j >= 200)   break;  // 常数优化if (dis[node[i].pos][node[j].pos] <= node[i].t - node[j].t)dp[i] = max(dp[i], dp[j] + node[i].val);}ans = max(ans, dp[i]);}cout << ans << endl;}return 0;
}

2020牛客寒假算法基础集训营3——J.牛牛的宝可梦Go【最短路 DP(01背包) 复杂度优化】(附优化分析)相关推荐

  1. 2020牛客寒假算法基础集训营3 B 牛牛的DRB迷宫II二进制详解

    2020牛客寒假算法基础集训营3 B 牛牛的DRB迷宫II B 牛牛的DRB迷宫II 输入: 25 输出: 5 5 RBBBR BBBBB BBBDB BDBBB RBBBB 题解 由图求方案数,我们 ...

  2. 2020牛客寒假算法基础集训营3 A.牛牛的DRB迷宫I

    2020牛客寒假算法基础集训营3 A.牛牛的DRB迷宫I 题目描述 牛牛有一个n*m的迷宫,对于迷宫中的每个格子都为'R','D','B'三种类型之一,'R'表示处于当前的格子时只能往右边走'D'表示 ...

  3. (构造+二进制)2020牛客寒假算法基础集训营3B.牛牛的DRB迷宫II

    2020牛客寒假算法基础集训营3B.牛牛的DRB迷宫II 思路: 一开始我是考虑全部都是B会怎么样,然后删改,结果到后面发现很难推到普遍规律(可能是因为我没看出来). 看了题解之后,觉得这题出的挺有意 ...

  4. 2020牛客寒假算法基础集训营1

    2020牛客寒假算法基础集训营1 honoka和格点三角形 题目描述 输入描述 输出描述 示例 解题思路 代码 kotori和bangdream 题目描述 输入描述 输出描述 示例 解题思路 代码 u ...

  5. 2021牛客寒假算法基础集训营1 J 一群小青蛙呱蹦呱蹦呱

    今天的比赛没打( 睡午觉去了,今天太累了 晚上来看看题 2021牛客寒假算法基础集训营1 J 一群小青蛙呱蹦呱蹦呱 题目传送门 板子题( 我们知道由唯一分解定理得,若 n=p1α1×p2α2×p3α3 ...

  6. 2021牛客寒假算法基础集训营2 D.牛牛与整除分块

    2021牛客寒假算法基础集训营2 D.牛牛与整除分块 题目链接 题目描述 整除分块,又称数论分块.是数论算法中的重要技巧,你可以在各种需要枚举因子的连续求和类问题中见到它的身影.如杜教筛,莫比乌斯反演 ...

  7. 2020牛客寒假算法基础集训营3

    链接:link 来源:牛客网 A 牛牛的DRB迷宫I 题目描述 牛牛有一个n*m的迷宫,对于迷宫中的每个格子都为'R','D','B'三种类型之一,'R'表示处于当前的格子时只能往右边走'D'表示处于 ...

  8. 2020牛客寒假算法基础集训营4

    链接:link 来源:牛客网 A 欧几里得 题目描述 现在,如果已知 g c d ( a , b ) gcd(a,b) gcd(a,b) 共递归了 n n n次,求所有可能的 a , b a,b a, ...

  9. 2020牛客寒假算法基础集训营5:B.牛牛战队的比赛地(二分/三分)

    整理的算法模板:ACM算法模板总结(分类详细版) 链接:https://ac.nowcoder.com/acm/contest/3006/B 来源:牛客网 题目描述 由于牛牛战队经常要外出比赛,因此在 ...

最新文章

  1. UE capability与 双连接相关的参数。
  2. java iterator map_Java循环遍历输出map方法
  3. 让使用SQLite的.NET应用自适应32位/64位系统
  4. XXI Open Cup. Grand Prix of Korea I. Query On A Tree 17 树剖 + 二分 + 树带权重心
  5. 仿58 php框架源码,转转最新源码
  6. Scala中class与object区别
  7. java反显是什么_卡西欧反显是什么意思
  8. opencv特效编辑之雕刻效果
  9. 远程办公软件华为云WeLink视频会议指南(下篇:记录会议纪要)
  10. Java定时任务与分布式定时任务
  11. iPad——添加学校邮箱到邮件解决方案
  12. “区块链+物联网”的发展现状和应用案例
  13. 迪普科技“高”在哪里?
  14. UVALive 7456 Least Crucial Node
  15. daliu_IT学习Android笔记第一篇--Android是什么?安卓的logo来源?安卓的发展过程?
  16. Mysql中Drop删除用户的名字_mysql中drop和delete方法删除用户的区别
  17. 编写各种outofmemory/stackoverflow程序
  18. k2虚拟服务器功能,配置图形加速的View虚拟桌面-NVIDIA GRID K2使用指南
  19. 通信原理中星座图详解
  20. 分享生活美好,三星Lifestyle系列电视和你一起拉满新年氛围

热门文章

  1. Linux下安装gitea
  2. java ctor_vue-test-utils设置获取TypeError:无法在字符串上创建属性'_Ctor'
  3. 各项异性扩散滤波 -- OpenCV实现
  4. android 联机游戏平台,游聚平台/街机平台/主机联网/街机对战平台/网络街机
  5. 第一回 网管是个苦差事
  6. 谁是淘宝创业主力军?平均年龄26 小镇青年占比高
  7. python实现m3u8转mp4方法2
  8. 机器学习和深度学习的区别
  9. 项目开发团队分配管理软件总结
  10. Cent OS7基础 第五节