题意:
分析
- 暴力
先 (floyd) 求出任意两点间的最短路,然后暴力枚举每一条边,是否存在于一个点对的最短路上,复杂度(O(mn^2))
- 正解
我们考虑能否将枚举边转化为枚举点,将复杂度降成(O(n^3))
这样就和社交网络一题类似,我们只需要统计出必经点的影响就可以了
那么问题转化为了什么时候必经边的个数等于这条边所连的必经点的个数
也就是说当对于这条边所连的一个点能通过这条边形成到另一个点的最短路时,必经边和必经点是等价的,所以我们处理出所有必经点的个数,然后枚举点
复杂度(O(n^3))
代码:
#include<bits/stdc++.h>
using namespace std;
namespace zzc
{
inline int read()
{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;
}
const int maxn = 505;
const int maxm = 3e5+5;
int n,m;
int d[maxn][maxn],e[maxn][maxn],num[maxn],ans[maxn][maxn];
void work()
{
int a,b,c;
memset(d,0x3f,sizeof(d));
memset(e,0x3f,sizeof(e));
n=read();m=read();
for(int i=1;i<=n;i++) d[i][i]=0;
for(int i=1;i<=m;i++)
{
a=read();b=read();c=read();
e[a][b]=e[b][a]=c;
d[a][b]=d[b][a]=c;
}
for(int k=1;k<=n;k++)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
}
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++) num[j]=0;
for(int j=1;j<=n;j++)
{
for(int k=1;k<=n;k++)
{
if(d[i][k]+e[k][j]==d[i][j]) num[j]++;
}
}
for(int j=1;j<=n;j++)
{
for(int k=1;k<=n;k++)
{
if(d[i][k]+d[k][j]==d[i][j]) ans[i][j]+=num[k];
}
}
}
for(int i=1;i<=n;i++)
{
for(int j=i+1;j<=n;j++)
{
if(d[i][j]>=0x3f3f3f) ans[i][j]=0;
printf("%d ",ans[i][j]);
}
}
}
}
int main()
{
zzc::work();
return 0;
}