J-xay loves Floyd
ANJHZ题解
abcdhhhh_题解
-
如果di,j=wi,j\text d_{i,j}=\text w_{i,j}di,j=wi,j,那么按照题意中的算法仍然能得到正确的结果。此时记cani,j=1\text{can}_{i,j}=1cani,j=1。
-
如果存在vvv,使得①cani,v=1\text{can}_{i,v}=1cani,v=1②canv,j=1\text{can}_{v,j}=1canv,j=1③vvv在iii到jjj的任意一条最短路上,那么cani,j=1\text{can}_{i,j}=1cani,j=1。
直接这么算can[i][j]can[i][j]can[i][j]复杂度太高,我们注意到can[i][∗]can[i][*]can[i][∗],can[∗][j]can[*][j]can[∗][j]的运算本质上是集合求交,可以利用bitset维护。
将can[i][∗]can[i][*]can[i][∗]记为bitset<N> fr[i]
,can[∗][j]can[*][j]can[∗][j]记为bitset<N>to[j]
同时,枚举sss,则sss到jjj的所有最短路经过的点集potj\text{pot}_jpotj也可以通过bitset维护,具体做法是每次枚举一个sss,就重新把顶点按照到sss的最短路长度排序,从小到大计算potj\text{pot}_jpotj。如果ds,k+wk,j=ds,j\text d_{s,k}+\text w_{k,j}=\text d_{s,j}ds,k+wk,j=ds,j,则potj∣=potk\text{pot}_j|=\text{pot}_kpotj∣=potk
时间复杂度O(nmlogm+n2ww)O(nm\log m+\frac{n^2w}{w})O(nmlogm+wn2w)
Code
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
template <class T=int> T rd()
{T res=0;T fg=1;char ch=getchar();while(!isdigit(ch)) {if(ch=='-') fg=-1;ch=getchar();}while( isdigit(ch)) res=(res<<1)+(res<<3)+(ch^48),ch=getchar();return res*fg;
}
const int N=2005,M=5005;
int h[N],e[M],ne[M],w[M],idx;
void add(int a,int b,int c){e[idx]=b,ne[idx]=h[a],w[idx]=c,h[a]=idx++;}
int d[N][N];
int n,m;
bool st[N];
bitset<N> pot[N],fr[N],to[N];void dij(int s,int d[])
{memset(st,0,sizeof st);priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>> q;q.push({d[s]=0,s});while(q.size()){int u=q.top().second;q.pop();if(st[u]) continue;st[u]=1;for(int i=h[u];i!=-1;i=ne[i]){int v=e[i];if(d[v]>d[u]+w[i]) {d[v]=d[u]+w[i];q.push({d[v],v});}}}for(int i=h[s];i!=-1;i=ne[i]){int v=e[i];if(w[i]==d[v]) fr[s][v]=to[v][s]=1;}
}
int solve(int s)
{static int id[N];for(int i=1;i<=n;i++){pot[i].reset();pot[i].set(i);}for(int i=1;i<=n;i++) id[i]=i;sort(id+1,id+1+n,[&](const int i,const int j){return d[s][i]<d[s][j];});for(int i=1;i<=n;i++){int u=id[i];for(int i=h[u];i!=-1;i=ne[i]){int v=e[i];if(d[s][u]+w[i]==d[s][v]) pot[v]|=pot[u];}}for(int i=1;i<=n;i++)if(d[s][i]==0x3f3f3f3f||(pot[i]&fr[s]&to[i]).count()) fr[s][i]=to[i][s]=1;return fr[s].count();
}
int main()
{n=rd(),m=rd();memset(d,0x3f,sizeof d);memset(h,0xff,sizeof h);for(int i=1;i<=n;i++){fr[i].reset();fr[i][i]=1;to[i].reset();to[i][i]=1;}while(m--){int u=rd(),v=rd(),c=rd();add(u,v,c);}for(int i=1;i<=n;i++) dij(i,d[i]);int ans=0;for(int i=1;i<=n;i++) ans+=solve(i);printf("%d\n",ans);
}