由于我太菜了,不会矩阵乘法,所以给同样不会矩阵乘法同学的福利

首先发现这题点很多边很少,实际上有用的点 \(<= 2 * T\)(因为每条边会触及两个点嘛)

所以我们可以把点的范围缩到 \(2 * T\)来,然后...

算法1 Bellman - Ford O(NT)

什么,限制边数?那不就是可爱的 \(BellmanFord\)吗?

看看复杂度,嗯嗯 \(10 ^ 8\) 海星,常数超小的我肯定不用吸氧的

#pragma GCC optimize(2)
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
const int N = 205, M = 105;
struct Edge{
int u, v, w;
}e[M];
int m, n, s, t, adj[N], dis[N], bDis[N], tot;
void inline read(int &x) {
x = 0;
char s = getchar();
while(s > '9' || s < '0') s = getchar();
while(s <= '9' && s >= '0') x = x * 10 + s - '0', s = getchar();
}
int inline get(int &x) {
return lower_bound(adj + 1, adj + 1 + tot, x) - adj;
} int inline bellmanFord(){
memset(dis, 0x3f, sizeof dis);
dis[s] = 0;
for(register int i = 1; i <= n; i++){
memcpy(bDis, dis, sizeof dis);
memset(dis, 0x3f, sizeof dis);
for(register int j = 1; j <= m; j++){
dis[e[j].v] = min(dis[e[j].v], bDis[e[j].u] + e[j].w);
dis[e[j].u] = min(dis[e[j].u], bDis[e[j].v] + e[j].w);
}
}
return dis[t];
} int main(){
read(n); read(m); read(s); read(t);
for (register int i = 1; i <= m; i++) {
read(e[i].w); read(e[i].u); read(e[i].v);
adj[++tot] = e[i].u;
adj[++tot] = e[i].v;
}
sort(adj + 1, adj + 1 + tot);
tot = unique(adj + 1, adj + 1 + tot) - adj - 1;
for (register int i = 1; i <= m; i++) {
e[i].u = get(e[i].u), e[i].v = get(e[i].v);
}
s = get(s), t = get(t);
printf("%d\n", bellmanFord());
return 0;
}

真香

算法2 倍增 + Floyd O(T ^ 3 * log_2N)

据说这题正解要用矩阵乘法,可我不会,咋办呢?

不如用倍增的思想,把\(N\)拆成二进制下的多个\(1\),我们把每个\('1'\)最短路搞出来,然后拼出来最终的最短路,先预处理:

\(d[i][j][l]\) 表示从 \(i\) 到 \(j\) 恰好经过 \(2 ^ l\) 条边的最短路。

初始化 \(d[i][j][0] = w[i][j]\),剩下为正无穷(注意是恰好 \(N\) 条边,所以 \(d[i][i][0]\) 也是非法状态)

转移也很好想:

\(d[i][j][l] = min(d[i][k][l - 1] + d[k][j][l - 1])\),对于一个状态 \(d[i][j][l]\),枚举中间点 \(k\) 即可,所以预处理复杂度 \(O(T ^ 3 * log_2N)\)

接下来用二进制拼起来就行辣~,设 \(g[i]\) 为这前几部走完后,从 \(s\) 到 \(i\) 的最短路, \(f[i]\) 为当前到 \(i\) 的最短路,与保卫王国的拼凑法思想差不多,即:

\(f[i] = min(g[j] + d[j][i][c])\) 若 \(N\) 的二进制第 \(c\) 位为 \(1\)。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
const int N = 205, M = 105;
struct Edge{
int u, v, w;
}e[M];
int m, n, s, t, adj[N], tot, d[N][N][20], f[N], g[N];
int L; int inline get(int x) {
return lower_bound(adj + 1, adj + 1 + tot, x) - adj;
}
int main(){
memset(d, 0x3f, sizeof d);
scanf("%d%d%d%d", &n, &m, &s, &t);
L = log2(n);
for (int i = 1; i <= m; i++) {
scanf("%d%d%d", &e[i].w, &e[i].u, &e[i].v);
adj[++tot] = e[i].u;
adj[++tot] = e[i].v;
}
sort(adj + 1, adj + 1 + tot);
tot = unique(adj + 1, adj + 1 + tot) - adj - 1;
for (int i = 1; i <= m; i++) {
int u = get(e[i].u), v = get(e[i].v), w = e[i].w;
d[u][v][0] = d[v][u][0] = min(d[u][v][0], w);
}
s = get(s), t = get(t); for (int c = 1; c <= L; c++) {
for (int i = 1; i <= tot; i++) {
for (int j = 1; j <= tot; j++) {
for (int k = 1; k <= tot; k++) {
d[i][j][c] = min(d[i][j][c], d[i][k][c - 1] + d[k][j][c - 1]);
}
}
}
} memset(g, 0x3f, sizeof g);
g[s] = 0;
for (int c = 0; c <= L; c++) {
if(n >> c & 1) {
memset(f, 0x3f, sizeof f);
for (int i = 1; i <= tot; i++)
for (int j = 1; j <= tot; j++)
f[i] = min(f[i], g[j] + d[j][i][c]);
memcpy(g, f, sizeof g);
}
}
printf("%d\n", f[t]);
return 0;
}

AcWing 345. 牛站 Cow Relays的更多相关文章

  1. P2886 [USACO07NOV]牛继电器Cow Relays

    题目描述 For their physical fitness program, N (2 ≤ N ≤ 1,000,000) cows have decided to run a relay race ...

  2. [洛谷P2886] 牛继电器Cow Relays

    问题描述 For their physical fitness program, N (2 ≤ N ≤ 1,000,000) cows have decided to run a relay race ...

  3. [USACO07NOV]牛继电器Cow Relays

    题目描述 给出一张无向连通图,求S到E经过k条边的最短路. 输入输出样例 输入样例#1: 2 6 6 4 11 4 6 4 4 8 8 4 9 6 6 8 2 6 9 3 8 9 输出样例#1: 10 ...

  4. 洛谷P2886 [USACO07NOV]牛继电器Cow Relays

    题意很简单,给一张图,把基本的求起点到终点最短路改成求经过k条边的最短路. 求最短路常用的算法是dijkstra,SPFA,还有floyd. 考虑floyd的过程: c[i][j]=min(c[i][ ...

  5. Luogu 2886 [USACO07NOV]牛继电器Cow Relays

    BZOJ 1706权限题. 倍增$floyd$. 首先这道题有用的点最多只有$200$个,先离散化. 设$f_{p, i, j}$表示经过$2^p$条边从$i$到$j$的最短路,那么有转移$f_{p, ...

  6. [USACO07NOV]牛继电器Cow Relays (最短路,DP)

    题目链接 Solution 非正解 似乎比较蛇啊,先个一个部分分做法,最短路+\(DP\). 在求最短路的堆或者队列中存储元素 \(dis_{i,j}\) 代表 \(i\) 这个节点,走了 \(j\) ...

  7. 洛谷 [P2886] 牛继电器Cow Relays

    最短路 + 矩阵快速幂 我们可以改进矩阵快速幂,使得它适合本题 用图的邻接矩阵和快速幂实现 注意 dis[i][i] 不能置为 0 #include <iostream> #include ...

  8. [LUOGU] P2886 [USACO07NOV]牛继电器Cow Relays

    https://www.luogu.org/problemnew/show/P2886 给定无向连通图,求经过k条边,s到t的最短路 Floyd形式的矩阵乘法,同样满足结合律,所以可以进行快速幂. 离 ...

  9. [luoguP2886] [USACO07NOV]牛继电器Cow Relays(矩阵)

    传送门 矩阵快速幂,本质是floyd 把 * 改成 + 即可 注意初始化 因为只有100条边,所以可以离散化 #include <cstdio> #include <cstring& ...

随机推荐

  1. python + appium 执行报错整理

    1.driver.find_element_by_id("com.taobao.taobao:id/searchEdit").send_keys("adidas" ...

  2. Fiddler的一系列学习瞎记2(没有章法的笔记)

    前言 不适合小白,因为很多需要小白来掌握的东西我都没有写,就是补充自己还不会的东西,所以,有些同僚看起来可能感觉不是很清楚. 正文: 瞎记2-什么是代理服务器 1.web代理服务器,是在客户端和服务器 ...

  3. Ceph OSD从filestore 转换到 bluestore的方法

    前言 前段时间看到豪迈的公众号上提到了这个离线转换工具,最近看到群里有人问,找了下没什么相关文档,就自己写了一个,供参考 实践步骤 获取代码并安装 git clone https://github.c ...

  4. 【开发实录】在鸿蒙开发板上使用websocket(移植自librws库)

    librws: Tiny, cross platform websocket client C library 相关代码可在下面下载,也可进入librws: 将librws移植到鸿蒙Hi_3861开发 ...

  5. Spring Cloud注册中心之Consul

    Consul简介 Consul是HashiCorp公司使用Golang语言开发的一中多服务解决方案工具,相比于其他服务注册中心来说,Consul的功能更为强大,丰富,其中最基本的功能包含下面几点(翻译 ...

  6. txt文件覆盖恢复

    1.txt文件恢复到之前保存的版本 2.电脑未重启 方式:如果你使用系统还原可以用"还原以前的版本"功能来轻松找回. 右击.txt文件-还原以前的版本-选择时间点-还原

  7. 单线程的Redis有哪些慢动作?

    持续原创输出,点击上方蓝字关注我 目录 前言 为什么 Redis 这么火? 键和值的保存形式? 为什么哈希表操作变慢了? 集合的操作效率? 有哪些数据结构? 不同操作的复杂度? 总结 前言 现在一提到 ...

  8. 新同事不讲“码”德,这SQL写得太野了,请耗子尾汁~

    今天来分享几个MySQL常见的SQL错误(不当)用法.我们在作为一个初学者时,很有可能自己在写SQL时也没有注意到这些问题,导致写出来的SQL语句效率低下,所以我们也可以自省自检一下. 1. LIMI ...

  9. 深度分析:Java 静态方法/变量,非静态方法/变量的区别,今天一并帮你解决!

    静态/非静态 方法/变量的写法 大家应该都明白静态方法/字段比普通方法/字段的写法要多一个static关键字,简单写下他们的写法吧,了解的可以直接略过 class Test{ // 静态变量 publ ...

  10. springboot项目启动报错Communications link failure

    环境情况,MySQL版本如下: 报错情况如下(看上去是和数据库有关): com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communi ...