2020牛客多校第五场A-Portal
https://ac.nowcoder.com/acm/contest/5670/A
题意
有一个n个点m条边的带权图,你一开始在1号点,你要按顺序完成k个任务,第i个任务是先去a[i]再走
到b[i]。当你走到一个点上的时候,你可以在这个点创建一个传送门。当同时存在两个传送门的时候,
你可以在传送门之间不耗代价地传送。如果已经存在了两个传送门,你想再创建一个,就必须选择之前
的一个传送门关掉(关掉这个操作不耗时间,并且是远程操作,不需要走过去)。问完成所有任务的最
短总行走距离。
题解
我们考虑两个传送门的位置,其中一个传送门的位置其实是没有用的,我们随时可以在当前所在的位置开一个传送门,而不是走到一个传送门的位置再进行传送。
目标是要走完所有的\(2k\)个点,我们把任务拆开,设状态\(f[i][q]\)表示完成i个任务,这次的传送门设在q的最小花费,那么有以下情况
- 直接从c[i-1]走到c[i]
- 从c[i-1]走到q,在q开启传送门,枚举上一次传送门的位置p,从q传送到p,再从p走到c[i]
- 从c[i-1]走到q,在q开启传送门,直接从q走到c[i]
- 从c[i-1]传送到p,从p走到q,在q开启传送门,再从q走到c[i]
Floyd预处理出两点间的最短距离,直接转移即可
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
struct READ {
inline char read() {
#ifdef _WIN32
return getchar();
#endif
static const int IN_LEN = 1 << 18 | 1;
static char buf[IN_LEN], *s, *t;
return (s == t) && (t = (s = buf) + fread(buf, 1, IN_LEN, stdin)), s == t ? -1 : *s++;
}
template <typename _Tp> inline READ & operator >> (_Tp&x) {
static char c11, boo;
for(c11 = read(),boo = 0; !isdigit(c11); c11 = read()) {
if(c11 == -1) return *this;
boo |= c11 == '-';
}
for(x = 0; isdigit(c11); c11 = read()) x = x * 10 + (c11 ^ '0');
boo && (x = -x);
return *this;
}
} in;
const int N = 350;
ll G[N][N];
int a[N<<1];
ll f[N<<1][N];
const ll inf = 0x3f3f3f3f3f3f3f3f;
int main() {
int n, m, k; in >> n >> m >> k;
memset(G, inf, sizeof(G));
for (int i = 1; i <= m; i++) {
int u, v; ll w; in >> u >> v >> w;
G[u][v] = min(G[u][v], w);
G[v][u] = min(G[v][u], w);
}
for (int i = 1; i <= n; i++) G[i][i] = 0;
k *= 2;
for (int i = 1; i <= k; i++) in >> a[i];
a[0] = 1;
for (int k = 1; k <= n; k++) {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
G[i][j] = min(G[i][j], G[i][k] + G[k][j]);
}
}
}
memset(f, inf, sizeof(f));
f[0][1] = 0;
for (int i = 1; i <= k; i++) {
for (int p = 1; p <= n; p++) {
if (f[i-1][p] != inf) f[i][p] = min(f[i][p], f[i-1][p] + G[a[i-1]][a[i]]);
for (int q = 1; q <= n; q++) {
f[i][q] = min(f[i][q], f[i-1][p] + G[a[i-1]][q] + G[p][a[i]]);
f[i][q] = min(f[i][q], f[i-1][p] + G[a[i-1]][q] + G[q][a[i]]);
f[i][q] = min(f[i][q], f[i-1][p] + G[p][q] + G[q][a[i]]);
}
}
}
ll ans = inf;
for (int i = 1; i <= n; i++) ans = min(ans, f[k][i]);
printf("%lld\n", ans);
return 0;
}