题意

一张无向图,每条边有权值,可以选择不超过 $k$ 条路使其权值变成0,求 $S$ 到 $T$ 的最短路。(同洛谷 P4568

分析

首先,分层图最短路可以有效解决这种带有 「阶段性」的最短路,这是分层图最短路的模板题。

建立 $0~k $ 层相同的图,每层之间相邻的节点之间也用权值为0的边相连(具体操作见代码)。第 $k$ 层表示已经将 $k$ 条道路置为0。最终把每层的终点连向一个超级汇点。最短路就是从第 $0$ 层源点到超级汇点的最短路。

#include<bits/stdc++.h>
using namespace std; const int maxn = 1e6 + ;
const int maxe = 1e7 + ; //仔细算算
const int INF = 0X3f3f3f3f; struct Edge
{
int to, w, next;
}edges[maxe];
int head[maxn], cnt;
int n, m, S, T, K; void init()
{
memset(head, -, sizeof(head));
cnt = ;
} inline void AddEdge(int a, int b, int w)
{
int id = ++cnt;
edges[id].to = b;
edges[id].w = w;
edges[id].next = head[a];
head[a] = id;
} struct Node
{
int u, d; //节点的编号与距离
bool operator < (const Node x) const
{
return d > x.d;
}
};
int vis[maxn], dis[maxn]; void Dijsktra(int s)
{
priority_queue<Node>q;
memset(vis, , sizeof(vis));
memset(dis, INF, sizeof(dis));
dis[s] = ;
q.push(Node{s, dis[s]});
while(!q.empty())
{
Node x = q.top();q.pop();
int u = x.u;
if(vis[u]) continue;
vis[u] = true;
for(int i = head[u]; i != -;i = edges[i].next)
{
int v = edges[i].to;
int w = edges[i].w;
if(!vis[v] && dis[u] + w < dis[v])
{
dis[v] = dis[u] + w;
q.push(Node{v, dis[v]});
}
}
}
} int main()
{
init();
scanf("%d%d%d%d%d", &n, &m, &S, &T, &K);
for(int i = ;i < m;i++)
{
int a, b, w;
scanf("%d%d%d", &a, &b, &w);
AddEdge(a, b, w);
AddEdge(b, a, w);
for(int j = ;j <= K;j++)
{
AddEdge(a+(j-)*n, b+j*n, );
AddEdge(b+(j-)*n, a+j*n, );
AddEdge(a+j*n, b+j*n, w);
AddEdge(b+j*n, a+j*n, w);
}
}
for(int i = ;i < K;i++) AddEdge(T+i*n, T+(i+)*n, ); //将每层终点连接到超级汇点
Dijsktra(S);
printf("%d\n", dis[T+K*n]); return ;
}

这题可以用分层图的思想来理解,但是可以用dp来写,只需对Dijsktra作一点修改,对 $dis$ 数组增加一维,$dis[i][j]$ 表示到第 $i$ 个点,用了 $j$ 次免费机会的最短路径长度。

分层图的方法比较直观,但是占用的内存较多。

#include<bits/stdc++.h>
using namespace std; const int maxn = 1e3 + ;
const int maxe = 2e3 + ; //仔细算算
const int maxk = 1e3 + ;
const int INF = 0X3f3f3f3f; struct Edge
{
int to, w, next;
}edges[maxe];
int head[maxn], cnt;
int n, m, S, T, K; void init()
{
memset(head, -, sizeof(head));
cnt = ;
} inline void AddEdge(int a, int b, int w)
{
int id = ++cnt;
edges[id].to = b;
edges[id].w = w;
edges[id].next = head[a];
head[a] = id;
} struct Node
{
int u, d, times; //节点的编号、距离和已经走0通道的次数
bool operator < (const Node x) const
{
return d > x.d;
}
};
int vis[maxn][maxk], dis[maxn][maxk]; void Dijsktra(int s)
{
priority_queue<Node>q;
memset(vis, , sizeof(vis));
memset(dis, INF, sizeof(dis));
dis[s][] = ;
q.push(Node{s, dis[s][], });
while(!q.empty())
{
Node x = q.top();q.pop();
int u = x.u, times = x.times;
if(vis[u][times]) continue;
vis[u][times] = true;
for(int i = head[u]; i != -;i = edges[i].next)
{
int v = edges[i].to, w = edges[i].w;
if(times < K && dis[u][times] < dis[v][times+]) //走0通道
{
dis[v][times+] = dis[u][times];
q.push(Node{v, dis[v][times+], times+});
}
if(dis[u][times] + w < dis[v][times]) //不走0通道
{
dis[v][times] = dis[u][times] + w;
q.push(Node{v, dis[v][times], times});
}
}
}
} int main()
{
init();
scanf("%d%d%d%d%d", &n, &m, &S, &T, &K);
for(int i = ;i < m;i++)
{
int a, b, w;
scanf("%d%d%d", &a, &b, &w);
AddEdge(a, b, w);
AddEdge(b, a, w);
}
Dijsktra(S);
int ans = INF;
for(int i = ;i <= K;i++) ans = min(ans, dis[T][i]);
printf("%d\n", ans); return ;
}

参考链接:

1. https://blog.csdn.net/SSL_ZYC/article/details/94959850

2. https://www.luogu.org/problemnew/solution/P4568?page=2

2019牛客多校第四场J free——分层图&&最短路的更多相关文章

  1. 2019牛客多校第四场J free 最短路

    free 题意 给出一个带权联通无向图,你需要从s走到t,你可以选择k条变让他们的权值为0问从s到t的最小权值是多少? 分析 思考一下,如果不带k条白嫖这个条件,那么这就是一个简单的dji就搞定了,我 ...

  2. 2019牛客多校第四场 I题 后缀自动机_后缀数组_求两个串de公共子串的种类数

    目录 求若干个串的公共子串个数相关变形题 对一个串建后缀自动机,另一个串在上面跑同时计数 广义后缀自动机 后缀数组 其他:POJ 3415 求两个串长度至少为k的公共子串数量 @(牛客多校第四场 I题 ...

  3. 2019牛客多校第四场 A meeting

    链接:https://ac.nowcoder.com/acm/contest/884/A来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 524288K,其他语言10485 ...

  4. 2019牛客多校第四场B xor——线段树&&线性基的交

    题意 给你 $n$ 个集合,每个集合中包含一些整数.我们说一个集合表示一个整数当且仅当存在一个子集其异或和等于这个整数.现在你需要回答 $m$ 次询问 ($l, r, x$),是否 $l$ 到 $r$ ...

  5. 2019牛客多校第四场A meeting——树的直径

    题意: 一颗 $n$ 个节点的树上标有 $k$ 个点,找一点使得到 $k$ 个关键结点的最大距离最小. 分析: 问题等价于求树的直径,最小距离即为直径除2向上取整. 有两种求法,一是动态规划,对于每个 ...

  6. [2019牛客多校第四场][G. Tree]

    题目链接:https://ac.nowcoder.com/acm/contest/884/G 题目大意:给定一个树\(A\),再给出\(t\)次询问,问\(A\)中有多少连通子图与树\(B_i\)同构 ...

  7. 2019牛客多校第四场D-triples I 贪心

    D-triples 题意 给你一个\(n\),问至少有几个数或运算起来可以等于\(n\),并且输出数量和这个几个数.题目说明给的\(n\)一定符合条件(不会输出\(n= 1\) 之类不存在情况). 思 ...

  8. 2019牛客多校第四场C-sequence(单调栈+线段树)

    sequence 题目传送门 解题思路 用单调栈求出每个a[i]作为最小值的最大范围.对于每个a[i],我们都要乘以一个以a[i]为区间内最小值的对应的b的区间和s,如果a[i] > 0,则s要 ...

  9. 2019牛客多校第四场K number dp or 思维

    number 题意 给一个数字串,问有几个子串是300的倍数 分析 dp写法:这题一看就很dp,直接一个状态dp[i][j]在第i位的时候膜300的余数是j左过去即可.这题比赛的时候样例老是少1,后面 ...

随机推荐

  1. [转帖]Greenplum :基于 PostgreSQL 的分布式数据库内核揭秘 (上篇)

    Greenplum :基于 PostgreSQL 的分布式数据库内核揭秘 (上篇) https://www.infoq.cn/article/3IJ7L8HVR2MXhqaqI2RA 学长的文章.. ...

  2. LC 173. Binary Search Tree Iterator

    题目描述 Implement an iterator over a binary search tree (BST). Your iterator will be initialized with t ...

  3. zabbix硬件监控以及服务

    大家好今天给大家带来zabbix3.4.8监控主机,那么最近由于我个人的关系.没有及时的更新文章所以,很抱歉那么今天我分享的内容是zabbix3.4.8监控服务器.本章的具体监控服务器如下: 服务器的 ...

  4. Pod——状态和生命周期管理及探针和资源限制

    一.什么是Podkubernetes中的一切都可以理解为是一种资源对象,pod,rc,service,都可以理解是 一种资源对象.pod的组成示意图如下,由一个叫”pause“的根容器,加上一个或多个 ...

  5. C# SHA512和Base64加解密方法

    /// <summary> /// Get SHA512 Hash From String /// </summary> /// <param name="or ...

  6. 怎样理解没有this的构造函数

    如果一个构造函数内部没有this, 那可以说这个压根不是构造函数, 因为他并不能返回一个实例对象; function Person(name) { var name = name; }; var li ...

  7. C#一些面试知识题

    1.简述 private. protected. public.internal 修饰符的访问权限答:private:私有成员, 在类的内部才可以访问(只能从其声明上下文中进行访问). protect ...

  8. Java Web 深入分析(5) Java ClassLoader 工作机制

    Classloader 有3个作用 将class加载到JVM中去 审查每个类由谁去加载,是一种父优先的等级加载 把Class字节码统一编译成JVM统一要求的对象格式 ClassLoader的等级加载机 ...

  9. 关于微信小程序获取view的动态高度填坑

    wx.createSelectorQuery().select('#box').boundingClientRect(function (rect) { width = rect.width heig ...

  10. socket基本用法

    socket介绍 1.什么是socket socket是应用层与传输层中间的一个软件抽象层,它是一组接口.它把TCP/IP这些复杂的协议统一封装起来 这样我们只要知道如何使用socket就好,就已经符 ...