这是本文档旧的修订版!
时间复杂度 $O(m\log m)$。
template <typename T> struct dijkstra{ T dis[MAXN]; bool vis[MAXN]; priority_queue<pair<T,int>,vector<pair<T,int> >,greater<pair<T,int> > >q; void solve(int src,int n){ mem(vis,0); _rep(i,1,n) dis[i]=Inf; dis[src]=0; q.push(make_pair(dis[src],src)); while(!q.empty()){ pair<T,int> temp=q.top();q.pop(); int u=temp.second; if(vis[u]) continue; vis[u]=true; for(int i=head[u];i;i=edge[i].next){ int v=edge[i].to; if(dis[v]>edge[i].w+dis[u]){ dis[v]=edge[i].w+dis[u]; q.push(make_pair(dis[v],v)); } } } } };
给定 $n$ 个城市,$m$ 条边以及起点、终点。
要求选择一条路径,满足路径边权和不超过给定值,且路径上的最大点权最小。
二分点权上界,跑 $\text{dijkstra}$ 时跳过点权大于该上界的点,计算起点到终点的边权和最短路,如果不超过给定值则更新答案。
时间复杂度 $O(n\log m\log v)$
平均时间复杂度 $O(Km)$,最坏时间复杂度 $O(nm)$。
template <typename T> struct SPFA{ T dis[MAXN]; int len[MAXN]; bool inque[MAXN]; bool solve(int src,int n){ queue<int>q; mem(inque,0);mem(len,0); _rep(i,1,n) dis[i]=Inf; dis[src]=0;len[src]=1; q.push(src); inque[src]=true; while(!q.empty()){ int u=q.front();q.pop(); inque[u]=false; for(int i=head[u];i;i=edge[i].next){ int v=edge[i].to; if(dis[v]>dis[u]+edge[i].w){ dis[v]=dis[u]+edge[i].w; len[v]=len[u]+1; if(len[v]>n) return false; if(!inque[v]){ q.push(v); inque[v]=true; } } } } return true; } };
解方程 $$ \left \{ \begin{array}{l} x_{a1}-x_{b1}\le y_1\\ x_{a2}-x_{b2}\le y_2\\ \cdots\\ x_{am}-x_{bm}\le y_m \end{array} \right. $$
将 $x_j-x_i\le y$ 移项,得 $x_j\le x_i+y$,发现该式与单源最短路的三角不等式 $\text{dist}_j\le \text{dist}_i+\text{w}_{i\to j}$ 相似。
考虑添加超级源点 $x_0$,$x_0$ 向所有其他点连一条权为 $0$ (事实上边权数值无特殊要求,边权相当于为所有解加上一个初始值)的单向边。
然后跑最短路算法即可,解得 $x_i=\text{dist}_i+k$ 为方程的一组可行解。
时间复杂度 $O(n^3)$,无法判断负环。
int n,dis[MAXN][MAXN]; void Floyd(){ _for(i,0,n) _for(j,0,n) dis[i][j]=Inf; _for(i,0,n) dis[i][i]=0; _for(k,0,n) _for(i,0,n) _for(j,0,n) dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]); }
给定 $n$ 个城市,$m$ 条边,每个城市在第 $t_i$ 天起才加入点集(保证 $t_i$ 升序)。
$q$ 个询问,每次询问第 $t$ 天的 $dis(i,j)$,保证询问的 $t$ 升序。
考虑 $\text{Floyd}$ 算法本质其实是 $\text{dp}$。
$dis[k][i][j]$ 表示只使用前 $k$ 个点作为中转点时 $i$、$j$ 间的最短路,可以用滚动数组省去一维。
所以本题只需要按时间更新即可。
时间复杂度 $O(nm\log m)$,带负环判断。
加入虚拟节点,虚拟节点向每个点连一条权值为 $0$ 的单向边。
跑一遍 $\text{SPFA}$,得到每个点到虚拟节点的距离,记该距离为每个点的势能 $h_i$。
将原图中的所有边权修改 $w+h_u-h_v$,则对每条路径 $s\to t$,有