2020牛客寒假算法基础集训营3——J.牛牛的宝可梦Go【最短路 DP(01背包) 复杂度优化】(附优化分析)
题目传送门
题目描述
牛牛所在的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背包) 复杂度优化】(附优化分析)相关推荐
- 2020牛客寒假算法基础集训营3 B 牛牛的DRB迷宫II二进制详解
2020牛客寒假算法基础集训营3 B 牛牛的DRB迷宫II B 牛牛的DRB迷宫II 输入: 25 输出: 5 5 RBBBR BBBBB BBBDB BDBBB RBBBB 题解 由图求方案数,我们 ...
- 2020牛客寒假算法基础集训营3 A.牛牛的DRB迷宫I
2020牛客寒假算法基础集训营3 A.牛牛的DRB迷宫I 题目描述 牛牛有一个n*m的迷宫,对于迷宫中的每个格子都为'R','D','B'三种类型之一,'R'表示处于当前的格子时只能往右边走'D'表示 ...
- (构造+二进制)2020牛客寒假算法基础集训营3B.牛牛的DRB迷宫II
2020牛客寒假算法基础集训营3B.牛牛的DRB迷宫II 思路: 一开始我是考虑全部都是B会怎么样,然后删改,结果到后面发现很难推到普遍规律(可能是因为我没看出来). 看了题解之后,觉得这题出的挺有意 ...
- 2020牛客寒假算法基础集训营1
2020牛客寒假算法基础集训营1 honoka和格点三角形 题目描述 输入描述 输出描述 示例 解题思路 代码 kotori和bangdream 题目描述 输入描述 输出描述 示例 解题思路 代码 u ...
- 2021牛客寒假算法基础集训营1 J 一群小青蛙呱蹦呱蹦呱
今天的比赛没打( 睡午觉去了,今天太累了 晚上来看看题 2021牛客寒假算法基础集训营1 J 一群小青蛙呱蹦呱蹦呱 题目传送门 板子题( 我们知道由唯一分解定理得,若 n=p1α1×p2α2×p3α3 ...
- 2021牛客寒假算法基础集训营2 D.牛牛与整除分块
2021牛客寒假算法基础集训营2 D.牛牛与整除分块 题目链接 题目描述 整除分块,又称数论分块.是数论算法中的重要技巧,你可以在各种需要枚举因子的连续求和类问题中见到它的身影.如杜教筛,莫比乌斯反演 ...
- 2020牛客寒假算法基础集训营3
链接:link 来源:牛客网 A 牛牛的DRB迷宫I 题目描述 牛牛有一个n*m的迷宫,对于迷宫中的每个格子都为'R','D','B'三种类型之一,'R'表示处于当前的格子时只能往右边走'D'表示处于 ...
- 2020牛客寒假算法基础集训营4
链接:link 来源:牛客网 A 欧几里得 题目描述 现在,如果已知 g c d ( a , b ) gcd(a,b) gcd(a,b) 共递归了 n n n次,求所有可能的 a , b a,b a, ...
- 2020牛客寒假算法基础集训营5:B.牛牛战队的比赛地(二分/三分)
整理的算法模板:ACM算法模板总结(分类详细版) 链接:https://ac.nowcoder.com/acm/contest/3006/B 来源:牛客网 题目描述 由于牛牛战队经常要外出比赛,因此在 ...
最新文章
- UE capability与 双连接相关的参数。
- java iterator map_Java循环遍历输出map方法
- 让使用SQLite的.NET应用自适应32位/64位系统
- XXI Open Cup. Grand Prix of Korea I. Query On A Tree 17 树剖 + 二分 + 树带权重心
- 仿58 php框架源码,转转最新源码
- Scala中class与object区别
- java反显是什么_卡西欧反显是什么意思
- opencv特效编辑之雕刻效果
- 远程办公软件华为云WeLink视频会议指南(下篇:记录会议纪要)
- Java定时任务与分布式定时任务
- iPad——添加学校邮箱到邮件解决方案
- “区块链+物联网”的发展现状和应用案例
- 迪普科技“高”在哪里?
- UVALive 7456 Least Crucial Node
- daliu_IT学习Android笔记第一篇--Android是什么?安卓的logo来源?安卓的发展过程?
- Mysql中Drop删除用户的名字_mysql中drop和delete方法删除用户的区别
- 编写各种outofmemory/stackoverflow程序
- k2虚拟服务器功能,配置图形加速的View虚拟桌面-NVIDIA GRID K2使用指南
- 通信原理中星座图详解
- 分享生活美好,三星Lifestyle系列电视和你一起拉满新年氛围