[2018.10.17 T2] 最优路线

版权声明:大佬您能赏脸,蒟蒻倍感荣幸,还请联系我让我好好膜拜。 https://blog.csdn.net/ShadyPi/article/details/83116130

暂无链接

最优路线

【题目描述】

一个 n n 个点 m m 条边的无重边无自环的无向图,点有点权,边有边权,定义一条路径的权值为路径经过的点权的最大值乘边权最大值。求任意两点间的权值最小的路径的权值。

【输入格式】

第一行两个整数 n , m n,m ,分别表示无向图的点数和边数。
第二行 n n 个正整数,第 i i 个正整数表示点 i i 的点权。
接下来 m m 行每行三个正整数 u i , v i , w i u_i,v_i,w_i ,分别描述一条边的两个端点和边权。

【输出格式】

n n 行每行 n n 个整数,第 i i 行第 j j 个整数表示从 i i j j 的路径的最小权值,如果从 i i 不能到达 j j ,则该值为 1 -1 。特别地,当 i = j i=j 时输出 0 0

【样例 1】
path. in

3 3
2 3 3
1 2 2
2 3 3
1 3 1

path.out

0 6 3
6 0 6
3 6 0

【样例 2】

见选手目录下 path. in/path.ans。

【数据范围与约定】

对于 20 % 20\% 的数据, n < = 5 , m < = 8 n<=5,m<=8
对于 50 % 50\% 的数据, n < = 50 n<=50
对于 100 % 100\% 的数据, n < = 500 , m < = n ( n 1 ) / 2 n<=500,m<=n*(n-1)/2 ,边权和点权不超过 1 0 9 10^9

题解

先考虑 50 50 分做法, d p [ i ] [ j ] [ k ] dp[i][j][k] 表示 i i j j ,路径上最长边长度为 k k 时最大点点权的最小值,类似 F l o y e d \mathcal{Floyed} 更新一下就可以做到 O ( n 4 ) O(n^4)

事实上,我们不需要那么麻烦, m x [ i ] [ j ] mx[i][j] 表示 i i j j 路径上最长边的最小值,使用 F l o y e d \mathcal{Floyed} 来更新,但是枚举中继点 k k 的时候我们要按点权从小到大枚举,这样 i i j j 路径上点权最大的点就一定是 i , j , k i,j,k 中的一个,于是便可以更新答案为 m i n ( a n s , m x [ i ] [ j ] × m a x ( v a l [ k ] , m a x ( v a l [ i ] , v a l [ j ] ) ) min(ans,mx[i][j]\times max(val[k],max(val[i],val[j]))

代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int M=505;
struct sd{int val,id;}pt[M];
bool operator<(sd a,sd b){return a.val<b.val;}
int val[M],mx[M][M],n,m;
ll ans[M][M];
void in()
{
	scanf("%d%d",&n,&m);
	memset(mx,127,sizeof(mx));
	for(int i=1;i<=n;++i)for(int j=1;j<=n;++j)if(i!=j)ans[i][j]=LONG_LONG_MAX;
	for(int i=1;i<=n;++i)scanf("%d",&val[i]),pt[i]=(sd){val[i],i};
	for(int i=1,a,b,c;i<=m;++i)scanf("%d%d%d",&a,&b,&c),mx[a][b]=mx[b][a]=c,ans[a][b]=ans[b][a]=1ll*max(val[a],val[b])*mx[a][b];
}
void ac()
{
	sort(pt+1,pt+1+n);
	for(int k=1;k<=n;++k)for(int i=1;i<=n;++i)for(int j=1;j<=n;++j)
	if(mx[i][j]>max(mx[i][pt[k].id],mx[pt[k].id][j]))
	mx[i][j]=max(mx[i][pt[k].id],mx[pt[k].id][j]),ans[i][j]=min(ans[i][j],1ll*mx[i][j]*max(pt[k].val,max(val[i],val[j])));
	for(int i=1;i<=n;++i,putchar(10))for(int j=1;j<=n;++j)printf("%lld ",ans[i][j]==LONG_LONG_MAX?-1:ans[i][j]);
}
int main(){in(),ac();}

猜你喜欢

转载自blog.csdn.net/ShadyPi/article/details/83116130
T2