1. 程式人生 > >[2018.10.17 T2] 最優路線

[2018.10.17 T2] 最優路線

暫無連結

最優路線

【題目描述】

一個 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();}