P6190 魔法
给一个\(n\)点\(m\)边的有向图,可以使用\(k\)次魔法,每次魔法将边权变为相反数,求从\(1\)至\(n\)的最短路。
\(n \le 100,m \le 2500,k \le 10^6\)
- \(k = 0\)
\(\texttt{Floyd}\)即可,设\(f_{i,j}\)为从\(i\)到\(j\)的最短路,初始化为\(inf\)(有边权或\(i=j\)除外),转移:
\[f_{i,j} = \min \{f_{i,k} + f_{k,j}\}
\]
- \(k = 1\)
枚举使用魔法的边权。
\[f_{1,i,j} = \min \{f_{0,i,u} + f_{0,v,j} - w \mid (u,v,w) \in \mathbf{E}\}
\]
- \(k > 1\)
\[f_{a + b,i,j} = \min \{f_{a,i,k} + f_{b,k,j}\}
\]
矩阵优化,\(\mathcal{O}(n ^ 3 \log {k} + n ^ 2 m + n ^ 3)\)
#include <bits/stdc++.h>
#include <time.h>
using namespace std;
#define int long long
const int N = 102, inf = 1e12;
int n, m, k;
struct Matrix
{
long long a[N][N];
void clear(long long x)
{
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
a[i][j] = x;
}
}
return;
}
} F, A;
struct edge
{
int from, to;
long long w;
};
edge E[2505];
int top = 0;
Matrix operator*(const struct Matrix &x, const struct Matrix &y)
{
Matrix ans;
ans.clear(inf);
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
for (int k = 1; k <= n; k++)
{
ans.a[i][j] = min(ans.a[i][j], x.a[i][k] + y.a[k][j]);
}
}
}
return ans;
}
void Floyd(void)
{
for (int k = 1; k <= n; k++)
{
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
F.a[i][j] = min(F.a[i][j], F.a[i][k] + F.a[k][j]);
}
}
}
return;
}
void Get_A(void)
{
A.clear(inf);
for (int k = 1; k <= m; k++)
{
int u = E[k].from, v = E[k].to;
long long w = E[k].w;
// printf("u = %d,v = %d,w = %lld\n", u, v, w);
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
A.a[i][j] = min(A.a[i][j], min(F.a[i][j], F.a[i][u] + F.a[v][j] - w));
// printf("i = %d,j = %d,k = %d\n", i, j, k);
}
}
}
return;
}
Matrix qmul(struct Matrix x, int p)
{
Matrix ans;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
ans.a[i][j] = F.a[i][j];
}
}
while (p)
{
if (p & 1)
{
ans = ans * x;
}
x = x * x;
p >>= 1;
}
return ans;
}
signed main(void)
{
// freopen("P6190.in", "r", stdin);
// freopen("P6190.out", "w", stdout);
scanf("%lld%lld%lld", &n, &m, &k);
F.clear(inf);
for (int i = 1; i <= n; i++)
F.a[i][i] = 0;
for (int i = 1; i <= m; i++)
{
int u, v;
long long w;
scanf("%lld%lld%lld", &u, &v, &w);
F.a[u][v] = w;
E[++top] = (edge){u, v, w};
}
Floyd();
// printf("Floyd : OK\n");
Get_A();
// printf("A : OK\n");
if (k == 0)
{
printf("%lld\n", F.a[1][n]);
return 0;
}
Matrix ans = qmul(A, k);
// ans = ans * F;
printf("%lld\n", ans.a[1][n]);
return 0;
}