深圳技术大学第六届程序设计竞赛 A题思路分享(带权限 Floyd,倍增)
https://cpc.csgrandeur.cn/csgoj/problemset/problem?pid=1511
题意概述
给定 \(n\) 个星系,每个星系 \(i\) 有互不相同的空间稳定度 \(A_i\)。
任意两个星系 \(u, v\) 之间有一条航道,基础能量消耗为 \(W_{u,v}\) 。
一次「量子跃迁」定义为从某个起点 \(u\) 移动到终点 \(v\) (\(u \neq v\)),跃迁过程中可以经过若干中间星系 \(x\),对于路径上的任意中间星系 \(x\),必须满足 \(A_x < \min(A_u, A_v)\)。
单次跃迁的能量消耗,等于经过边的 \(W\) 之和。
现有 \(Q\) 次询问,每次询问给出 \(S, T\),求在恰好 \(K\) 次跃迁的前提下从 \(S\) 到达 \(T\) 的最小总能量消耗。如果无法到达,输出 \(-1\)。
\(3 \le N \le 150,1 \le K \le 10^9,1 \le Q \le 10^6\) 。
思路
先考虑建图。
记原图的距离矩阵为 \(W\),得到的图的矩阵为 \(adj\)。按 \(a_i\) 大小枚举中间点松弛,第 \(k\) 轮松弛之后,经过所有中间点 \(a_i\) 均 \(\le a_{ord_k}\),因此可以对所有满足 \(\min(a_s,a_t) \gt a_{ord_k}\) 的点对更新 \(adj\) 。
建完图后,预处理倍增数组 \(dp\),\(dp[i][j][k]\) 表示从 \(i\) 出发跳 \(2^k\) 步到 \(j\) 的最小距离。然后枚举 \(K\) 的二进制有效位,此时必须跳跃 \(2^k\) 步,记答案数组为 \(res\),转移方程:
\[nres[i][j] = \min(nres[i][j],res[i][p]+dp[p][j][k])
\]
之后每个询问都可以 \(\mathcal{O}(1)\) 完成。
时间复杂度 \(\mathcal{O}(n^3 \log K)\) 。
代码
//author:kzssCCC
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll INF = 9e18;
void solve(){
int n,K;
cin >> n >> K;
vector<ll> a(n+1);
for (int i=1;i<=n;i++){
cin >> a[i];
}
vector<vector<ll>> W(n+1,vector<ll>(n+1));
for (int i=1;i<=n;i++){
for (int j=1;j<=n;j++){
cin >> W[i][j];
if (W[i][j]==-1){
W[i][j] = INF;
}
}
}
vector<int> ord(n+1);
iota(ord.begin(),ord.end(),0);
sort(ord.begin()+1,ord.end(),[&](int i,int j){
return a[i]<a[j];
});
auto adj = W;
for (int tt=1;tt<=n;tt++){
for (int i=1;i<=n;i++){
if (W[i][ord[tt]]==INF) continue;
for (int j=1;j<=n;j++){
if (W[ord[tt]][j]==INF) continue;
W[i][j] = min(W[i][j],W[i][ord[tt]]+W[ord[tt]][j]);
if (a[ord[tt]]<min(a[i],a[j])){
adj[i][j] = min(adj[i][j],W[i][j]);
}
}
}
}
vector<vector<vector<ll>>> dp(n+1,vector<vector<ll>>(n+1,vector<ll>(32,INF)));
for (int i=1;i<=n;i++){
for (int j=1;j<=n;j++){
if (i==j) continue;
dp[i][j][0] = min(dp[i][j][0],adj[i][j]);
}
}
for (int k=1;k<32;k++){
for (int p=1;p<=n;p++){
for (int i=1;i<=n;i++){
if (dp[i][p][k-1]==INF) continue;
for (int j=1;j<=n;j++){
if (dp[p][j][k-1]==INF) continue;
dp[i][j][k] = min(dp[i][j][k],dp[i][p][k-1]+dp[p][j][k-1]);
}
}
}
}
vector<vector<ll>> res(n+1,vector<ll>(n+1,INF));
for (int i=1;i<=n;i++){
res[i][i] = 0;
}
for (int k=31;k>=0;k--){
if (K>>k&1){
vector<vector<ll>> nres(n+1,vector<ll>(n+1,INF));
for (int p=1;p<=n;p++){
for (int i=1;i<=n;i++){
if (res[i][p]==INF) continue;
for (int j=1;j<=n;j++){
if (dp[p][j][k]==INF) continue;
nres[i][j] = min(nres[i][j],res[i][p]+dp[p][j][k]);
}
}
}
res = nres;
}
}
int q;
cin >> q;
while (q--){
int s,t;
cin >> s >> t;
if (res[s][t]==INF){
cout << -1 << '\n';
}
else{
cout << res[s][t] << '\n';
}
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int t = 1;
// cin >> t;
while (t--) solve();
return 0;
}

浙公网安备 33010602011771号