E-DPRS 简解——2026牛客暑期多校训练营4
E-DPRS 简解
给定强连通带权有向图,\(n\) 点 \(m\) 边,第 \(k\) 条边为 \((u_k,v_k,w_k)\)。\(dis(i,j)\) 为 \(i\) 到 \(j\) 的最短路。图的值为 \(\max_{1\le i,j\le n, i\ne j} \frac{dis(i,j)}{dis(j,i)}\)。\(q\) 次独立询问:给定边 \(k\) 和新权 \(x\)(\(1\le x<w_k\)),临时将第 \(k\) 条边权改为 \(x\),求修改后图的值,之后恢复。
输入:\(T\) 组测试(\(1\le T\le 1000\))。每组 \(n,m,q\)(\(2\le n\le m\le 2000\),\(1\le q\le 2000\)),\(\sum n,\sum m,\sum q\le 2000\)。接下来 \(m\) 行 \(u_k,v_k,w_k\)(\(1\le u_k,v_k\le n\),\(u_k\ne v_k\),\(1\le w_k\le 10^9\)),保证强连通。接下来 \(q\) 行 \(k,x\)(\(1\le k\le m\),\(1\le x<w_k\))。
输出:每个询问一行实数,绝对或相对误差不超过 \(10^{-6}\)。
应该是出得非常好的一道最短路图论题,而且官方题解写得也非常生动易懂,这里仅仅是将此题放在博客上供个人复习,故写得较为简陋且与官解重复。
记 \(d(x,y)\) 为图中 \(x\) 到 \(y\) 的最短路,最重要的结论是,图的价值就为
由于 \(w\geq dis(u,v)\quad e=(u,v,w)\),于是 \(M\leq ans\)。
\(ans\leq M\),证明如下(官方题解证明,有点巧妙):
任取两个不同的点 \(s, t\),考虑一条从 \(t\) 到 \(s\) 的最短路
\(p_0 = t \to p_1 \to \cdots \to p_k = s\),其中第 \(i\) 条边的边权为 \(w_i\)。
于是 \(d(t, s) = \sum_{i=1}^{k} w_i\)。从 \(s\) 返回 \(t\) 时,可以依次走每条边对应的反向最短路,因此\[d(s, t) \leq \sum_{i=1}^{k} d(p_i, p_{i-1}) \leq \sum_{i=1}^{k} M w_i = M d(t, s). \]所以 \(\frac{d(s,t)}{d(t,s)} \leq M\),结论得证。
综上 \(M=ans\)
于是在已知任意两点 \(u,v\) 最短距离的情况下,只需要所有枚举 \(m\) 条边即可计算答案。假设当前修改的边为 \(a\to b\) 的一条边权为 \(w\) 的边,修改后边权 \(x<w\),记新图中两点最短路为 \(d_x(u,v)\),则
此外注意枚举到 \((a,b,w)\) 这条边时,这条边的边权已经为 \(x\),分母改变了,具体实现见代码。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll>ttfa;
const int N=2003;
const ll INF=0x3f3f3f3f3f3f3f3f;
int n,m,ques;
int uu[N],vv[N];ll ww[N];
vector<ttfa>tar[N];
ll dis[N][N];bool vis[N];
int main(){
int Test;scanf("%d",&Test);
while(Test--){
scanf("%d%d%d",&n,&m,&ques);
for(int i=1;i<=n;++i)tar[i].clear();
for(int i=1;i<=m;++i){
scanf("%d%d%lld",&uu[i],&vv[i],&ww[i]);
tar[uu[i]].push_back({vv[i],ww[i]});
}
priority_queue<ttfa,vector<ttfa>,greater<ttfa>>q;
for(int i=1;i<=n;++i)for(int j=1;j<=n;++j)dis[i][j]=INF;
for(int x=1;x<=n;++x){
for(int i=1;i<=n;++i)vis[i]=0;
dis[x][x]=0;q.push({0,x});
while(!q.empty()){
int u=q.top().second;q.pop();
if(vis[u])continue;
vis[u]=1;
for(auto [v,w]:tar[u]){
if(dis[x][v]>dis[x][u]+w){
dis[x][v]=dis[x][u]+w;
q.push({dis[x][v],v});
}
}
}
}
for(int T=1;T<=ques;++T){
int id,a,b;ll x;scanf("%d%lld",&id,&x);
double ans=0;
a=uu[id],b=vv[id];
for(int i=1;i<=m;++i){
int u=uu[i],v=vv[i];
ll w=(i==id?x:ww[i]);
ans=max(ans,1.0*min(dis[v][u],dis[v][a]+x+dis[b][u])/w);
}
printf("%.10lf\n",ans);
}
}
return 0;
}

浙公网安备 33010602011771号