题目大意:
一个n个点m条边的无重边无自环的无向图,点有点权,边有边权,定义一条路径的权值为路径经过的点权的最大值乘边权的最大值。
求任意两点间的权值最小的路径的权值。(1<=n<=500)
解题思路:
看到n<=500就想到了弗洛伊德算法,但怎么处理呢?
普通的弗洛伊德算法是按点的标号顺序枚举k的,这里我们可以按点权从小到大的顺序枚举k,那么计算时任意两点间的最大点值只能是i,j,k中的一个,现在就只用维护i,j之间路径的最大边的最小值即可。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<ctime>
#define ll long long
using namespace std;
int getint()
{
int i=0,f=1;char c;
for(c=getchar();(c<'0'||c>'9')&&c!='-';c=getchar());
if(c=='-')f=-1,c=getchar();
for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
return i*f;
}
const int N=505,inf=2e9;
const ll INF=2e18;
int n,m;
struct node
{
int val,id;
inline friend bool operator <(const node &a,const node &b)
{
return a.val<b.val;
}
}a[N];
int g[N][N];
ll f[N][N];
int main()
{
//freopen("path.in","r",stdin);
//freopen("path.out","w",stdout);
int x,y,z,mx;
n=getint(),m=getint();
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
f[i][j]=INF,g[i][j]=inf;
for(int i=1;i<=n;i++)
f[i][i]=g[i][i]=0,a[i].val=getint(),a[i].id=i;
while(m--)
{
x=getint(),y=getint(),z=getint();
g[x][y]=g[y][x]=z;
}
sort(a+1,a+n+1);
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
x=a[i].id,y=a[j].id,z=a[k].id;
g[x][y]=min(g[x][y],max(g[x][z],g[z][y]));
if(i<=k&&j<=k)f[x][y]=min(f[x][y],1ll*a[k].val*g[x][y]);//只用讨论i,j均小于k的情况,因为i,j>k的话下次k循环到i,j时也会处理。
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
if(f[i][j]!=INF)cout<<f[i][j]<<' ';
else cout<<-1<<' ';
cout<<'\n';
}
return 0;
}