CF1737D 题解
可以发现最优决策肯定是把一条边
问题转化成:给定一条边,求挪动次数最小值。
首先我们可以发现,挪动次数与边权无关,因此我们可以首先将原图上的边权置为
随后我们可以发现,一个端点
然后分情况讨论
-
两点分别走到
1,n 两点。
例:dis(u,1) + dis(v,n) -
枚举中转点
j 。其中一个点走到j 点,随后让另一个点一步挪动到j 点,再分别走到1,n 两点。这里的中转点可以是1/n 。
例:dis(u,j) + 1 + dis(j,1) + dis(j,n)
预处理复杂度
int T, n, m, t1, t2;
ll ans;
struct {int u, v, w;} e[N];
int g[501][502];
int main() {
get(T);
while (T--) {
get(n, m); rep(i,1,n) rep(j,1,n) if (i != j) g[i][j] = inf; ans = infll;
rep(i,1,m) get(e[i].u, e[i].v, e[i].w), g[e[i].u][e[i].v] = g[e[i].v][e[i].u] = 1;
rep(k,1,n) rep(i,1,n) rep(j,1,n) g[i][j] = min(g[i][j], g[i][k] + g[k][j]);
rep(i,1,m) {
int now = min( {g[1][e[i].u] + g[e[i].v][n], g[1][e[i].v] + g[e[i].u][n]} );
rep(j,1,n) now = min( {now, g[e[i].u][j] + 1 + g[1][j] + g[j][n], g[e[i].v][j] + 1 + g[1][j] + g[j][n]} );
ans = min(ans, 1ll * e[i].w * (now + 1));
} cout << ans << '\n';
}
}