问题:给定一张有n个点,m条有向边的图。一个整数k。(n<=1e5,m<=2e5,k<=10)。你有k次机会使得图中的某一条边权值变为0。求1号点到n号点的最短距离。保证至少存在一条路径从1到n。
思路:dijkstra算法+dp转移
这其实就是一道分层最短路的模板题。普通的dijkstra算法,dis数组记录的是起点到该点的最短距离,这里的话多开一维就好了。dis[i][j],代表起点到i点并且使用了j次机会的最短距离。转移时候分情况使用或不使用这次机会讨论来进行转移。因为k不超过10,所以空间复杂度和时间复杂度都是合理的。然后其他操作就和普通的dijkstra算法是一样的。具体见代码。
AC代码:
//#include<bits/stdc++.h>
#include<set>
#include<map>
#include<stack>
#include<cmath>
#include<ctime>
#include<queue>
#include<cstdio>
#include<string>
#include<vector>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<unordered_map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<ll, int> pli;
typedef pair<int, ll> pil;
#define pb push_back
#define X first
#define Y second
inline ll gcd(ll a, ll b) { while (b != 0) { ll c = a % b; a = b; b = c; }return a < 0 ? -a : a; }
inline ll lcm(ll a, ll b) { return (a * b) / gcd(a, b); }
inline ll lowbit(ll x) { return x & (-x); }
const double PI = 3.14159265358979323846;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const ll mod = 998244353;
inline char nc() {
static char buf[1 << 21], * p1 = buf, * p2 = buf;
return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++;
}
inline ll rd() {
//#define getchar nc
ll x = 0, f = 1; char ch = getchar();
while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar(); }
return x * f;
}
const double eps = 1e-6;
const int M = 1e6 + 10;
const int N = 1e5 + 10;
struct Edge {
int to, next;
ll w;
}e[N << 1];
int head[N];
int tot;
int n, m, k;
inline void add(int x, int y, ll w) {
e[++tot] = { y,head[x],w };
head[x] = tot;
}
ll dis[N][13];
bool vis[N][13];
struct MM {
int node, use;
ll val;
bool friend operator<(const MM& m1, const MM& m2) {
return m1.val > m2.val;
}
};
priority_queue<MM>q;
inline ll dijkstra() {
q.push({ 1,0 ,0 });
dis[1][0] = 0;
while (q.size()) {
int x = q.top().node, use = q.top().use; q.pop();
if (x == n) return dis[x][use];
if (vis[x][use])continue;
vis[x][use] = 1;
for (int i = head[x]; i != -1; i = e[i].next) {
int y = e[i].to;
if (dis[y][use] > dis[x][use] + e[i].w) {//这一次不白嫖
dis[y][use] = dis[x][use] + e[i].w;
q.push({ y,use,dis[y][use] });
}
if (use < k && dis[y][use + 1] > dis[x][use]) {//这次白嫖
dis[y][use + 1] = dis[x][use];
q.push({ y,use + 1,dis[y][use + 1] });
}
}
}
}
void init() {
tot = 0;
memset(head, -1, sizeof(head[0]) * (n + 5));
memset(dis, INF, sizeof(dis[0]) * (n + 5));
memset(vis, 0, sizeof(vis[0]) * (n + 5));
while (q.size())q.pop();
}
int main() {
int t = rd();
while (t--) {
n = rd(), m = rd(), k = rd();
init();
while (m--) {
int u = rd(), v = rd();
ll w = rd();
add(u, v, w);
}
printf("%lld\n", dijkstra());
}
}
京公网安备 11010502036488号