CF416E President’s Path
题面:
题面翻译
对于 n n n 个点 m m m 条边的简单无向图(无重边、自环),记 f ( s , t ) f(s,t) f(s,t) 为 R s , t R_{s,t} Rs,t 类边的数量。 R s , t R_{s,t} Rs,t 类边是指这样一类边:存在一条从 s s s 到 t t t 的最短路,满足这条边在最短路上。
对于每一对 s , t s,t s,t ,你都要计算出 f ( s , t ) f(s,t) f(s,t) 的值。
输入格式
先是 n , m ( 2 ≤ n ≤ 500 , 0 ≤ m ≤ n ( n − 1 ) 2 ) n,m(2\le n\le 500,0\le m\le \frac{n(n-1)}{2}) n,m(2≤n≤500,0≤m≤2n(n−1)) ,含义见题面。
接下来 m m m 行表述边 ( x i , y i , l i ) (x_i,y_i,l_i) (xi,yi,li) ,分别为连接的两个点的编号,边的长度。
输出格式
仅输出一行,包含 n ( n − 1 ) 2 \frac{n(n-1)}{2} 2n(n−1) 个数。前 n − 1 n-1 n−1 个数为 f ( 1 , 2 ) , f ( 1 , 3 ) , … , f ( 1 , n ) f(1,2),f(1,3),\dots,f(1,n) f(1,2),f(1,3),…,f(1,n) ;接下来 n − 2 n-2 n−2 个数为 f ( 2 , 3 ) , f ( 2 , 4 ) , … , f ( 2 , n ) f(2,3),f(2,4),\dots,f(2,n) f(2,3),f(2,4),…,f(2,n) ;以此类推。
样例 #1
样例输入 #1
5 6 1 2 1 2 3 1 3 4 1 4 1 1 2 4 2 4 5 4
样例输出 #1
1 4 1 2 1 5 6 1 2 1
观察 n n n 的数据范围,自然想到跑 f l o y d floyd floyd.
我们如果枚举每一条边,判断是否在最短路上,
对于最短路边 ( u , v ) (u,v) (u,v):
d i s i , j = d i s i , u + d i s v , j + w ( u , v ) dis_{i,j} = dis_{i,u} + dis_{v,j} + w(u,v) disi,j=disi,u+disv,j+w(u,v)
时间复杂度是 O ( n 4 ) \mathcal{O}(n^4) O(n4) 不能接受.
考虑优化到 O ( n 3 ) \mathcal{O}(n^3) O(n3),
枚举点是否在最短路上,
对于最短路点 k k k:
d i s i , j = d i s i , k + d i s k , j dis_{i,j} = dis_{i,k} + dis_{k,j} disi,j=disi,k+disk,j
令 d p i , j dp_{i,j} dpi,j 为 i ⇝ j i \rightsquigarrow j i⇝j 上最短边的个数,
根据最短路(一条链)的性质,对于 i ⇝ k ⇝ j i \rightsquigarrow k \rightsquigarrow j i⇝k⇝j,我们考虑以计算 ( x , k ) (x,k) (x,k) 边的个数,累加到 d p i , j dp_{i,j} dpi,j 。
我们如何计算 ( x , k ) (x,k) (x,k) 呢?
我们将边备份给 g i , j g_{i,j} gi,j,然后对于 i ⇝ k i\rightsquigarrow k i⇝k 计算 i ⇝ x → k i \rightsquigarrow x \rightarrow k i⇝x→k 的个数,用:
d i s i , k = d i s i , x + g x , k dis_{i,k} = dis_{i,x} + g_{x,k} disi,k=disi,x+gx,k
判断。
然后枚举起点 i i i,以上述方法更新 d p i , j dp_{i,j} dpi,j
AC-code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
int rd() {
int x = 0, w = 1;
char ch = 0;
while (ch < '0' || ch > '9') {
if (ch == '-') w = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = x * 10 + (ch - '0');
ch = getchar();
}
return x * w;
}
void wt(int x) {
static int sta[35];
int f = 1;
if(x < 0) f = -1,x *= f;
int top = 0;
do {
sta[top++] = x % 10, x /= 10;
} while (x);
if(f == -1) putchar('-');
while (top) putchar(sta[--top] + 48);
}
constexpr int N = 505,inf = 0x3f3f3f3f3f3f3f3fLL;
int n,m,f[N][N],g[N][N],dp[N][N],con[N];
signed main() {
n = rd(),m = rd();
for(int i = 1;i<=n;i++)
for(int j = 1;j<=n;j++)
f[i][j] = f[j][i] = g[i][j] = g[j][i] = inf;
for(int i = 1;i<=m;i++) {
int u = rd(),v = rd(),w = rd();
g[u][v] = g[v][u] = f[u][v] = f[v][u] = min(w,f[u][v]);
}
for(int i = 1;i<=n;i++) f[i][i] = 0;
for(int k = 1;k<=n;k++)
for(int i = 1;i<=n;i++)
for(int j = 1;j<=n;j++)
f[j][i] = f[i][j] = min(f[i][j],f[i][k] + f[k][j]);
for(int i = 1;i<=n;i++) {
for(int j = 1;j<=n;j++) con[j] = 0;
for(int j = 1;j<=n;j++)
for(int k = 1;k<=n;k++)
if(f[i][k] + g[k][j] == f[i][j])
con[j]++;
for(int j = 1;j<=n;j++)
for(int k = 1;k<=n;k++)
if(f[i][k] + f[k][j] == f[i][j])
dp[i][j] += con[k];
}
for(int i = 1;i<=n;i++)
for(int j = i + 1;j<=n;j++) {
if(f[i][j] >= inf) dp[i][j] = 0;
wt(dp[i][j]),putchar(' ');
}
return 0;
}