2019牛客多校第四场J free——分层图&&最短路
题意
一张无向图,每条边有权值,可以选择不超过 $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——分层图&&最短路的更多相关文章
- 2019牛客多校第四场J free 最短路
free 题意 给出一个带权联通无向图,你需要从s走到t,你可以选择k条变让他们的权值为0问从s到t的最小权值是多少? 分析 思考一下,如果不带k条白嫖这个条件,那么这就是一个简单的dji就搞定了,我 ...
- 2019牛客多校第四场 I题 后缀自动机_后缀数组_求两个串de公共子串的种类数
目录 求若干个串的公共子串个数相关变形题 对一个串建后缀自动机,另一个串在上面跑同时计数 广义后缀自动机 后缀数组 其他:POJ 3415 求两个串长度至少为k的公共子串数量 @(牛客多校第四场 I题 ...
- 2019牛客多校第四场 A meeting
链接:https://ac.nowcoder.com/acm/contest/884/A来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 524288K,其他语言10485 ...
- 2019牛客多校第四场B xor——线段树&&线性基的交
题意 给你 $n$ 个集合,每个集合中包含一些整数.我们说一个集合表示一个整数当且仅当存在一个子集其异或和等于这个整数.现在你需要回答 $m$ 次询问 ($l, r, x$),是否 $l$ 到 $r$ ...
- 2019牛客多校第四场A meeting——树的直径
题意: 一颗 $n$ 个节点的树上标有 $k$ 个点,找一点使得到 $k$ 个关键结点的最大距离最小. 分析: 问题等价于求树的直径,最小距离即为直径除2向上取整. 有两种求法,一是动态规划,对于每个 ...
- [2019牛客多校第四场][G. Tree]
题目链接:https://ac.nowcoder.com/acm/contest/884/G 题目大意:给定一个树\(A\),再给出\(t\)次询问,问\(A\)中有多少连通子图与树\(B_i\)同构 ...
- 2019牛客多校第四场D-triples I 贪心
D-triples 题意 给你一个\(n\),问至少有几个数或运算起来可以等于\(n\),并且输出数量和这个几个数.题目说明给的\(n\)一定符合条件(不会输出\(n= 1\) 之类不存在情况). 思 ...
- 2019牛客多校第四场C-sequence(单调栈+线段树)
sequence 题目传送门 解题思路 用单调栈求出每个a[i]作为最小值的最大范围.对于每个a[i],我们都要乘以一个以a[i]为区间内最小值的对应的b的区间和s,如果a[i] > 0,则s要 ...
- 2019牛客多校第四场K number dp or 思维
number 题意 给一个数字串,问有几个子串是300的倍数 分析 dp写法:这题一看就很dp,直接一个状态dp[i][j]在第i位的时候膜300的余数是j左过去即可.这题比赛的时候样例老是少1,后面 ...
随机推荐
- [转帖]超能课堂(199) 接口渐趋统一,USB4又如何能引领变革?
https://www.expreview.com/70414.html 接口协议真复杂.. 9月3日,USB IF正式公布了USB4(你没看错,就是USB4,没有空格)的技术规格.USB-IF表示, ...
- ORA-01078: failure in processing system parameters LRM-00109: could not open parameter file '/u01/app/oracle/product/19.2.0/db_1/dbs/initsanshi.ora'报错
本人是在Linux安装Oracle19C之后,启动数据库时,XSHELL命令行窗口报的该错误,看了几个解决方案之后,总结如下 从字面的意思来看,是在dbs目录当中没有这个initsanshi.ora文 ...
- 【CodeForces】868F. Yet Another Minimization Problem
原题链接 题目大意是有N个数,分成K段,每一段的花费是这个数里相同的数的数对个数,要求花费最小 如果只是区间里相同数对个数的话,莫队就够了 而这里是!边单调性优化边莫队(只是类似莫队)!而移动的次数和 ...
- LeetCode_#1_两数之和 Two Sum_C++题解
1. 两数之和 Two Sum 题目描述 Given an array of integers, return indices of the two numbers such that they ad ...
- Java RadixSort
Java RadixSort /** * <html> * <body> * <P> Copyright 1994-2018 JasonInternational ...
- MarkDown 语法记录
Markdown是一种纯文本格式的标记语言.通过简单的标记语法,它可以使普通文本内容具有一定的格式. 为啥要用 MarkDown 呢? 优点 1.因为是纯文本,所以只要支持Markdown的地方都能获 ...
- 冒泡(bubblesort)、选择排序、插入排序、快速排序
冒泡排序(bubblesort) 特点:通过换位置的方式,一直向上冒泡 package main import "fmt" func bubbleSortAsc(arrayA [] ...
- vue + element-ui 国际化实现
1. 安装组件和插件 cnpm i element-ui -S // 安装elementcnpm i vue-i18n -S //安装i18n 2.将国际化资源放在assets目录下 3.在src下新 ...
- 现有项目springmvc 小结
1. 接口接收json数据 @RequestBody JSONObject param 2.返回json数据封装 DataPacket.jsonResult
- MMU简介
MMU(Memory Management Unit)内存管理单元 负责虚拟地址到物理地址的映射,并提供硬件机制的内存访问权限检查.内存访问权限的检查可以保护每个进程所用的内存不会被其他进程所破坏 地 ...