B. 阿强的路
题意:
-
“所有这两点间的路径中能得到的最小的路径最大点权乘以路径最大边权”
就这句话,断句很重要!!!
如果跟我一样断在“最小的路径”后面(小学语文水平),那就完全错了,就一直想着在最短路上跑,泡了个寂寞
要断在“最小的”后面,就是对于任意两点的所有路径,找到一条路径,这条路径上的最大点权乘最大边权是所有路径最小的那条
分析:
-
多源点路径 D P DP DP
-
多源点路径上的问题,可以想到在 F l o y d Floyd Floyd 上跑
-
为什么要排序?
-
同时维护两个东西:最大边权和最大点权
在状态转移的时候:
即在跑 F l o y d Floyd Floyd 的过程中,是一个一个地往图上加点,对于当前加入的点,当且仅当它的点权比之前的所有点权都要大的时候,才不会影响到之后的状态
否则,若先加入一个大的点,之后的状态加入一个更小的点,当两个点都比某一对 ( u , v ) (u,v) (u,v) 大时,本该选择前者大的点(因为要选最大点权),但是会选了后者,这样就会对最后的结果造成影响
因此,要先按点权从小到大排序,为了让大的后出现
-
讲的不是很清楚,求助能讲清楚的好心人,在评论区指出
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=505;
struct Node
{
int id,w;
bool operator < (const Node &b) const { return w<b.w; }
}a[N];
int ew[N][N],f[N][N],pw[N];
signed main()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>a[i].w;
a[i].id=i; pw[i]=a[i].w;
}
sort(a+1,a+1+n);
memset(f,0x3f,sizeof(f));
memset(ew,0x3f,sizeof(ew));
for(int i=1;i<=m;i++)
{
int u,v,w;
cin>>u>>v>>w;
ew[u][v]=ew[v][u]=min(ew[u][v],w); // 最小化边权
f[u][v]=f[v][u]=min(f[u][v],ew[u][v]*max(pw[u],pw[v]));
// max(pw[u],pw[v]),初始状态下取两端点的大的那端
}
//Floyd
for(int k=1;k<=n;k++)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(ew[i][j]>max(ew[i][a[k].id],ew[a[k].id][j]))
{ // 当出现最大边权小于当前的时,更新最大边权及f[i][j]
ew[i][j]=max(ew[i][a[k].id],ew[a[k].id][j]);
f[i][j]=f[j][i]=min(f[i][j],ew[i][j]*max({pw[i],pw[j],a[k].w}));
// 就是这里的a[k].w,一定要小的在前面,才不会影响过程当中的状态
}
}
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(i==j) { cout<<"0 "; continue; }
if(ew[i][j]>1e18) cout<<"-1"<<' ';
else cout<<f[i][j]<<' ';
}
cout<<endl;
}
}