Magic Girl Haze

T组

n个点,m条有向含权边,可以选择不超过k条边,将其权值变为0.

问点1到点n的最短距离是多少?

1≤T≤5n≤105m≤2×105k≤10wi≤109
1\leq T \leq 5 \\
n \leq 10^5 \\
m \leq 2\times10^5 \\
k \leq 10 \\
w_i \leq 10^9
1≤T≤5n≤105m≤2×105k≤10wi​≤109

二维状态Dijkstra

原本dijkstra算法是dis[v],只有点的编号一个维度,dis[v]状态表示的是1到v最短的距离。

现在令dis[k][v]表示恰好k条边变0,点1到v最短的距离,状态变为二维

原本是uuu到vvv有边就可以尝试状态转移

现在是

  1. (k,u)(k,u)(k,u)到(k,v)(k,v)(k,v)可以转移,代价w;
  2. (k,u)(k,u)(k,u)到(k+1,u)(k+1,u)(k+1,u)可以转移,代价0;

正确性是显然的

对于状态k=k0,∀u(k,u)k = k_0,\forall u(k,u)k=k0​,∀u(k,u),假设它们的初始值已经设置好了,则固定k=k0k=k_0k=k0​,它们之间的转移更新就是传统的一维dijkstra,因此是正确的

k=k0,∀u(k,u)k = k_0,\forall u (k,u)k=k0​,∀u(k,u)初始值本是无穷大, 但是k=K0−1k=K_0-1k=K0​−1的状态可以优化它们的初始值。

code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int t;
ll n, m;
int k;
const int maxn = 1e+5 + 5;
const int maxm = 2e+5 + 5;
const int maxk = 10;
vector<int> ev[maxn];
vector<ll> ew[maxn];
// bool solved[maxk + 1][maxn];
bool vis[maxk + 1][maxn];
ll dis[maxk + 1][maxn];
struct vnd
{
int v;
ll dis;
bool operator<(const struct vnd &obj) const
{
return dis > obj.dis;
}
void print() const {
cout << "(v,dis) = "<<v<<","<<dis<<endl;
}
};
priority_queue<vnd> q[maxk + 1]; void init()
{
cin >> n >> m >> k;
for (int u = 1; u <= n; ++u)
{
ev[u].clear();
ew[u].clear();
}
int u, v, w;
for (int i = 1; i <= m; ++i)
{
cin >> u >> v >> w;
ev[u].push_back(v);
ew[u].push_back(w);
}
// memset(solved, false, sizeof(solved));
memset(vis, false, sizeof(vis));
for (int i = 0; i <= k; ++i)
q[i] = priority_queue<vnd>();
} int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin >> t;
while (t--)
{
init();
bool first = true;
ll ans;
vis[0][1] = true;
dis[0][1] = 0;
int u, v;
ll w;
for (int i = 0; i <= k; ++i)
{
// push visited vertices into queue
for (int u = 1; u <= n; ++u)
if (vis[i][u]) {
q[i].emplace(vnd{u,dis[i][u]});
}
while (!q[i].empty())
{
vnd t = q[i].top();
q[i].pop();
u = t.v;
for (size_t j = 0; j < ev[u].size(); ++j)
{
v = ev[u][j];
w = ew[u][j];
// do not change w
if (!vis[i][v])
{
vis[i][v] = true;
dis[i][v] = t.dis + w;
q[i].emplace(vnd{v,dis[i][v]});
}
else if (dis[i][v] > t.dis + w)
{
dis[i][v] = t.dis + w;
q[i].emplace(vnd{v,dis[i][v]});
}
// change w to 0
if (i + 1 > k)
continue;
if (!vis[i + 1][v])
{
vis[i + 1][v] = true;
dis[i + 1][v] = t.dis;
}
else if (dis[i + 1][v] > t.dis)
{
dis[i + 1][v] = t.dis;
}
}
}
if (vis[i][n])
{
if (first)
{
first = false;
ans = dis[i][n];
}
else
{
ans = min(ans, dis[i][n]);
}
}
}
// the input ensure: first == false
cout << ans << endl;
}
return 0;
}

A1958的更多相关文章

  1. ICPC 2018 南京网络赛 J Magical Girl Haze(多层图最短路)

    传送门:https://nanti.jisuanke.com/t/A1958 题意:n个点m条边的路,你有k次机会将某条路上的边权变为0,问你最短路径长度 题解:最短路变形,我们需要在常规的最短路上多 ...

随机推荐

  1. VueJs一步步实现带感的帮助面板

    环境 IDE: WebStorm 2019.1.4 系统: Mac OS X 10.15.4 VueJs: 2.6.11 Vue-cli: 4.2.2 前言   最近一直在忙毕设,前端终于还是对我这个 ...

  2. Debian 10 安装无线网卡驱动 (rtl8822be)

    apt install firmware-realtek

  3. thinkPHP中Model的字段映射问题

    在model定义中不要自己定义相应的字段变量,因为一旦定义,之后的赋值会直接赋给自己定义的属性,但实际上model抽象类重写了__set()方法,将未定义的属性存入了$data里面,写入数据库是也会从 ...

  4. 实验一  GIT 代码版本管理

    实验一  GIT 代码版本管理 实验目的: 1)了解分布式分布式版本控制系统的核心机理: 2)熟练掌握git的基本指令和分支管理指令: 实验内容: 1)安装git 2)初始配置git ,git ini ...

  5. Maven 仓库、坐标、常用命令

    maven中的仓库 需要jar包时,先到本地仓库中找,没有就从中央仓库去下载到本地仓库. 中央仓库很多都在国外,下载速度慢.国内的一些公司在自己的服务器上搭建了maven仓库(中央仓库的镜像),供内部 ...

  6. redis 5.0.7 源码阅读——字典dict

    redis中字典相关的文件为:dict.h与dict.c 与其说是一个字典,道不如说是一个哈希表. 一.数据结构 dictEntry typedef struct dictEntry { void * ...

  7. Linux学习Day3:新手必须掌握的Linux命令(二)

    今天学习的命令都是运维工作中经常要用到的,非常实用,必须要用心学习,争取把这些命令烂熟于心,具体内容如下: 一.系统状态监测命令 1.ifconfig命令 用于获取网卡配置与网络状态等信息. [roo ...

  8. (vue操作storage)Vue plugin for work with local storage,session storage and memo

    vue-ls https://www.npmjs.com/package/vue-ls NPM npm install vue-ls --save Yarn yarn add vue-ls Usage ...

  9. 抖音快手短视频去水印API,接口开发文档

    开发者官网:http://api.lingquan166.com/ 简介:根据抖音.微视.小红书.皮皮搞笑等APP中复制出来的链接,解析获取短视频的标题.封面.无水印短视频地址等信息. 接口地址: h ...

  10. 【Java】简易Socket连接实现

    客户端: import java.io.*; import java.net.Socket; import java.text.SimpleDateFormat; import java.util.D ...