CF416E President‘s Path 题解

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(2n500,0m2n(n1)) ,含义见题面。

接下来 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(n1) 个数。前 n − 1 n-1 n1 个数为 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 n2 个数为 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 ij 上最短边的个数,

根据最短路(一条链)的性质,对于 i ⇝ k ⇝ j i \rightsquigarrow k \rightsquigarrow j ikj,我们考虑以计算 ( 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 ik 计算 i ⇝ x → k i \rightsquigarrow x \rightarrow k ixk 的个数,用:

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值