• 本题主要考察两个知识点:数论中的扩展欧几里得算法和图论中的迪杰斯特拉算法,都是经典常用的好算法,记不清楚的童鞋可以百度一下~
  • 此类题目我们很容易猜到要用图论中的一些算法,但是更重要的是如何抽象出 “图中的点” 以及 “图中点与点之间的连线权重”,因为往往题目中显式提出的点和线,不能直接看作我们要处理的“图”中的点和线。
  • 本题也是一样,真正被看作迪杰斯特拉算法中的“点”的,其实是疫苗运输线路,或者说是运输车,点与点之间是否存在连线取决于两条运输线路上的运输车是否能在同一时间到达同一站点,连线的权重则是最早在同一站点相遇的时间。
  • 这样想明白后,思路就清晰了(加引号的表述指的是迪杰斯特拉算法中的图对应的概念):先依次遍历所有线路经过的所有站点,凡是经过1站点的线路,都可以初始化该线路最早获取疫苗的时间为首次经过1站点的时间,即这些“点”和“起点”有连线。然后使用迪杰斯特拉算法,每轮选取一个获取疫苗时间最早的,且之前未选取过的线路,然后针对该线路经过的站点,依次使用扩展欧几里得算法,判断是否可以通过该站点转运到其他线路,即判断其是否与其他“点”存在连线,并计算出“权重”,然后根据迪杰斯特拉算法更新各“点”的“最短路径”。
  • 经过上述处理后,各线路获取疫苗的的站点和最早时间等数据都已知晓,只需依次遍历各线路经过的站点,更新其最早获取疫苗的时间即可。
  • 下面具体介绍一下如何使用扩展欧几里得算法计算两个线路是否可以同时到达交点处,以下图中的两条线路为例:

  1. 假设左边的车从编号为2的点走到1号点后,又转了X圈,右边的车从起点走到2号点后,又转了Y圈后在交点相遇,令a = a + d,则有等式a + b * X = x + y * Y,我们求出最小的非负X即可得到第一次相遇的时间(这里当X为非负时,Y一定也非负,因为y>x,若Y<0,则等式右边<0,而等式左边在X非负时一定大于0)。整理等式得到:b * X - y * Y = x - a。可以使用扩展欧几里得算法求解。
  2. 对于 a * x + b * y=c,当gcd(a, b)能整除c的时候,x, y存在解。使用扩展欧几里得算法首先求出a * x + b * y = gcd(a,b)的解x, y,然后还需要扩大c / gcd(a, b)倍可以得到一个解x0,y0。
  3. 我们可以使用扩展欧几里得算法求解,假设我们得到一组解x0,y0,则所有解的通式为:
    {x=x0+b/d∗k,y=y0−a/d∗k,k⊆Z}\left\{ x=x0 + b/d * k, y = y0 - a/d * k, k \subseteq Z \right\}{x=x0+b/d∗k,y=y0−a/d∗k,k⊆Z}
  4. 我们需要求解的是最小的正整数x,关于x的通式为:x=x0 + b/d * k,令b /= d,则最后的结果为
    (x0 % b + b) % b,这里为什么求余之后再加b,是因为负数求余可能是负数,例如:
    -5 % 7 = -5,-9 % 7 = -2。

代码如下:

#include <iostream>
#include <vector>
#include <cstring>
#include <algorithm>using namespace std;typedef long long LL;
typedef pair<int, int> PII;const int N = 510;
const LL INF = 0x3f3f3f3f3f3f3f3fll;int n, m;   // n个物流站,m条线路
int len[N];  // 每一条线路的总用时
struct Node {  // 存储线路信息int cid;  // 线路idint distance;  // 当前线路内的站点pid到起点的距离int pid;  // 线路上的站点赋予的pid,从0开始编号(起点为0,但是站点号不一定和编号相同)
};
// ps[ver] = {{1, 100, j}, {4, 150, k}}: 表示经过站点ver的线路有线路1和线路4
// 线路1编号为j的点经过此站点,j距离线路1的起点(编号为0)为100
vector<Node> ps[N];
// line[i][j] = {ver, y}: 表示线路i上编号(pid)为j的站点ver到下一个站点的距离(时间)是y
vector<PII> line[N];
LL dist[N];  // 每辆车最早拿到疫苗的时间, 通过该时间可以更新该线路上其他点最早拿到疫苗的时间
LL ans[N];  // 每个站点最早拿到疫苗的时间
bool st[N];  // dijkstra中的判重数组
// 存储每条线路最早拿到疫苗的点,例如pid[2]=1: 表示线路2最早拿到疫苗的点编号为1(Node中的pid)
int pid[N];LL cal_gcd(LL a, LL b, LL& x, LL& y) {  // 求x, y, 使得ax + by = gcd(a, b)if (!b) {x = 1, y = 0;return a;}LL d = cal_gcd(b, a % b, y, x);y -= (a / b) * x;return d;
}void dijkstra()  // 求1号点到n号点的最短路距离
{memset(dist, 0x3f, sizeof dist);for (int i = 0; i < m; i++) {int d = 0;for (int j = 0; j < line[i].size(); j++) {if (line[i][j].first == 1) { // 如果线路i上的第j个点站点号是1的话,说明可以作为起点dist[i] = d;    // 类似于迪杰斯特拉算法图中的点和起点直接相连,权重为时间pid[i] = j;     // 线路i上最早获得疫苗的点的编号是jbreak;}d += line[i][j].second;}}for (int i = 0; i < m; i++) {int tmp = -1;for (int j = 0; j < m; j++) {   //选取一个不在集合中的,到起点距离最短的“点”,此处判断条件颇耐人寻味~if (!st[j] && (tmp==-1 || dist[j] < dist[tmp]))tmp = j;}st[tmp] = true;auto d = dist[tmp];for (int j = pid[tmp], k = 0; k < line[tmp].size(); k++, j = (j + 1) % line[tmp].size()) {for (auto& c : ps[line[tmp][j].first]) {if (st[c.cid]) continue;LL a = d, b = len[tmp];LL x = c.distance, y = len[c.cid];// 扩展欧几里得算法LL X, Y;LL D = cal_gcd(b, y, X, Y);if ((x - a) % D) continue; //不能同时到达交点,则迪杰斯特拉图中的两点无连线X = (x - a) / D * X;y /= D;X = (X % y + y) % y;if (dist[c.cid] > a + b * X) {//dijkstra更新路径dist[c.cid] = a + b * X;pid[c.cid] = c.pid;}}d += line[tmp][j].second;}}
}int main()
{scanf("%d%d", &n, &m);for (int i = 0; i < m; i++) {int cnt, sum=0;scanf("%d", &cnt);for (int j = 0; j < cnt; j++) {int ver, t;scanf("%d%d", &ver, &t);ps[ver].push_back({ i, sum, j });line[i].push_back({ ver, t });sum += t;}len[i] = sum;}dijkstra();memset(ans, 0x3f, sizeof ans);for (int i = 0; i < m; i++) {if (dist[i] == INF) continue;LL d = dist[i];for (int j = pid[i], k = 0; k < line[i].size(); j = (j + 1) % line[i].size(), k++) {int ver = line[i][j].first;ans[ver] = min(ans[ver], d);d += line[i][j].second;}}for (int i = 2; i <= n; i++) {if (ans[i] == INF) puts("inf");else printf("%lld\n", ans[i]);}return 0;
}

csp 2021-04-05 疫苗运输相关推荐

  1. 荣耀机试题 2021.04 ~05

    记录下最近面试的算法题 题目记得不是特别清楚了,大致描述. 一 2021.04.17荣耀机试 1 数组排序 题目描述:输入多个数字,按数字从小到大排序. 输入描述 多个整数,保证都在int范围内,用空 ...

  2. linux机试题,智一面之荣耀机试题 2021.04 ~05

    记录下最近面试的算法题 题目记得不是特别清楚了,大致描述. 一 2021.04.17荣耀机试 1 数组排序 题目描述:输入多个数字,按数字从小到大排序. 输入描述 多个整数,保证都在int范围内,用空 ...

  3. 【2021.04.05】成功解决OBS录屏黑屏问题

    1.点击"设置"-"系统"-"显示"-"图形设置"-"浏览" 2.然后点击"OBS程序&q ...

  4. 2021年 第12届 蓝桥杯 Java B组 省赛真题详解及小结【第1场省赛 2021.04.18】

    蓝桥杯 Java B组 省赛决赛 真题详解及小结汇总[题目下载.2013年(第4届)~2020年(第11届)] CSDN 蓝桥杯 专栏 2013年 第04届 蓝桥杯 Java B组 省赛真题详解及小结 ...

  5. 2021年05月软件设计师真题透析

    2021年05月软件设计师上午真题及答案解析 1. 在 CPU 中,用( )给出将要执行的下一条指令在内存中的地址. A.程序计数器 B.指令寄存器 C.主存地址寄存器 D.状态条件寄存器 答案:A, ...

  6. Go 中 time.Parse 报错:year/month/day hour/minute/second out of range 时间格式化为什么是 2006-01-02 15:04:05?

    1. 问题现象 在使用 Go 语言的 time.Parse 解析时间时遇到以下错误: func main() {timeParse, err := time.Parse("2006-11-0 ...

  7. DotNetNuke 04.05.05 安装

    预备条件: 1.下载DotNetNuke 04.05.05 安装版或源代码版 http://sourceforge.net/project/downloading.php?group_id=77052 ...

  8. 【R】【课程笔记】04+05 数据预处理+收益率计算

    本文是课程<数据科学与金融计算>第4-5章的学习笔记,主要介绍金融数据处理.收益率计算和R与C++调用,用于知识点总结和代码练习,Q&A为问题及解决方案. 往期回顾: 博文 内容 ...

  9. Russ Cox:这不是Go项目的标准布局 | Gopher Daily (2021.04.28) ʕ◔ϖ◔ʔ

    每日一谚:Profile before you decide something is performance critical. Go技术生态 Go web开发的当前状态 - https://tno ...

  10. Go webrtc项目pion创始人专访 | Gopher Daily (2021.04.07) ʕ◔ϖ◔ʔ

    每日一谚:Go makes error handling as important as any other code Go技术生态 go webrtc项目pion的创始人专访 - https://w ...

最新文章

  1. nodejs文件上传报错总结
  2. opcuaclient 文档_连接协议-OPC UA Client
  3. mysql多实例(mysqld_multi方式)
  4. bzoj1096 [ZJOI2007]仓库建设
  5. 表格序号_如何让表格序号自动更新,四个函数让表格实现自动化、高效操作
  6. asp.net学习之ado.net(连接模式访问)
  7. Oracle数据库的trigger(触发器)
  8. Ubuntu 时间同步
  9. linq to entity常用操作
  10. 【kafka】kerberos Server not found in Kerberos database LOOKING_UP_SERVER Identifier doesn‘t match
  11. oracle cost小 比较慢,Oracle数据库中有关CBO优化的三个问题
  12. 2015-11-16
  13. python json.dumps()函数输出json格式,使用ensure_ascii参数对中文输入的支持
  14. 3月第3周安全回顾 大规模网页攻击 百万张信用卡数据丢失
  15. 安卓脚本怎么实现在后台_用按键精灵录制微信自动摇一摇脚本
  16. 《计算机导论》学后感想,学习《计算机导论》后的感想.doc
  17. Phalanx——二维dp
  18. AdGuard更多规则推荐
  19. matlab图像网格化像素提取像素扩大图片分块
  20. Fabrice Bellard其人

热门文章

  1. 腾讯轻量云linux系统dd安装windows
  2. java实现图像模版匹配(蜗牛学院)
  3. SEO优化中首页的标题应该把网站名称放在开头还是最后好?
  4. Keyshot一种不错的金属质感材料
  5. 各种会议名称的英文名称
  6. 计算机教学能力大赛实施报告模板,教学能力大赛获奖作品-课程标准(WORD版)对标教学实施报告(3页)-原创力文档...
  7. 计算机hash函数开题报告,自组网位置服务中基于哈希函数的位置分配和检索方法【开题报告+文献综述+毕业论文】...
  8. Python 数据结构之元组
  9. java毕业设计消防安全应急培训管理平台源码+lw文档+mybatis+系统+mysql数据库+调试
  10. php mysql 字段不为空_mysql如何查看字段是否为空