题意

一张无向图,每条边有权值,可以选择不超过 $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. MongoDB 聚合函数及排序

    聚合函数 最大值  $max db.mycol.aggregate([{$group : {_id : "$by_user", num_max : {$max: "$li ...

  2. pandas数据结构之Series笔记

    对Series的理解也源于对其相关的代码操作,本次仅贴一些代码来加深理解以及记忆 import pandas as pd import numpy as np s = pd.Series(np.ran ...

  3. Go语言学习笔记(5)——集合Map

    集合Map map是使用hash表实现的.无序的键值对的集合!只能通过key获得value,而不能通过index. map的长度不固定,和slice一样都是引用类型.len函数适用于map,返回map ...

  4. Android 使用自定义Drawable 设置圆角矩形或者圆形图片

    转自  Android Drawable 那些不为人知的高效用法 本文出自:[张鸿洋的博客] http://blog.csdn.net/lmj623565791/article/details/437 ...

  5. win7 bios引导启动Ubuntu

    用easyBCD修改系统启动项更改 1.安装easyBCD后打开,点击“Add New Entry”>选择Linux/BSD:具体设置如图,Type选择GRUB2,Name自己随便写,笔者写的是 ...

  6. 关于element ui滚动条使用

    element ui 自带的滚动条使用 在容器的直接外层添加 (需要展现滚动条的那一级) <el-scrollbar style="height:100%"></ ...

  7. iOS 如何判断一个点在圆、方框、三角形区域内?

    如何判断一个点是不是在方框(CGRect).圆(Circle).三角形(Triangle)内呢? 1.方框 //苹果官方方法可以判断 + (BOOL)point:(CGPoint)point inSq ...

  8. Missing Push Notification Entitlement解决方法

    原委 最近提交APP到Apple Store审核,结果很快就收到Apple很"贴心"的邮件.原文如下: Dear developer, We have discovered one ...

  9. leetcode-104.二叉树最大深度 · BTree + 递归

    easy 题就不详细叙述题面和样例了,见谅. 题面 统计二叉树的最大深度. 算法 递归搜索二叉树,返回左右子树的最大深度. 源码 class Solution { public: int maxDep ...

  10. 【Hibernate】持久化对象状态及以及缓存

    一.持久化类状态 1.1 三种持久化对象的状态 1.2 区分三种状态 1.3 三种状态对象转换 1.瞬时态 2.持久态 3.脱管态 4.持久态对象有自动更新数据库的能力 一.持久化类状态 1.1 三种 ...