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,后面 ...
随机推荐
- centos 防火墙相关命令
防火墙关闭: systemctl stop firewalld systemctl disable firewalld 重启防火墙: systemctl enable firewalld system ...
- Visual Studio中Debug与Release以及x86、x64、Any CPU的区别
Visual Studio中Debug与Release的区别: 在Visual Studio中,编译模式有2种:Debug与Release.这也是默认的两种方式,在新建一个project的时候,就已经 ...
- php微信小程序生成二维码,出现乱码,{"errcode":44002,"errmsg":"empty post data"},'{"errcode":41001,"errmsg":"access_token missing hint: [OoC.2a0822e255]"}',以及其他的坑
微信小程序的坑简直比我的头发还多,今天下午获取微信二维码,遇到的44002,41001,还有图片没法正常显示以及小程序参数获取的问题,接下来一一解决 首先获取微信token然后再获取二维码这个没什么好 ...
- 1205: 求一元二次方程的实数根(C)
一.题目 acm.wust.edu.cn/problem.php?id=1205&soj=0 二.分析 一元二次方程有三个系数a.b.c,两个根x1.x2,以及d(德尔塔): a.b.c均为实 ...
- Python 同级目录import报错
在使用protobuf时,我们自己了各种Options的时候,在生成的python文件会在同级目录中引用,所以这个时候我们不能做到,加个__init__.py文件了事然后在文件里面写 import m ...
- SAS学习笔记5 字符截取语句(index、compress、substr、scan函数)
index:返回一个字符串中,某个特定字符或字符串的位置,找不到时返回0 compress:从一个字符串移除特定的字符 substr函数 字符替换与提取字符 substr(s, p, n)从变量s的第 ...
- ASP.NET Core 过滤器
继承Attribute,IActionFilter实现自己的过滤器类,并且在Startup,mvc服务中注入. 全局都会过滤,在任意一个controller,action执行前和执行后都会过滤一次 通 ...
- atomikos 优化JDBC性能
JDBC performance comes for free with our pooling DataSource classes: AtomikosDataSourceBean for XA-e ...
- (十一)Hibernate中的多表操作(1):单向一对多
一.单向一对多() 案例一(用XML文件配置): 一个班级有多个学生,班级可以查看所有学生的信息. ClassBean.java package bean; import java.util.Hash ...
- (十三)JSON的使用(下)
(接上一章节) 4.2 使用ajax交互方式 使用ajax的转换思想 A:异步请求在页面中发起,也要在页面中接收数据并展现. B:ajax中的数据不能从作用域中获取,只能从respons ...