rt,悬赏两个关注+膜拜大佬
第一篇题解的思路,写法非常通俗。f[i][0/1/2]表示从i出发在k+1长度以内能达到的最大/次大/次次大的节点权值
ok(i,j)判断i在k+1步内能否到j
bfs n遍预处理,双重循环判断
#include<bits/stdc++.h>
#define PII pair<int,int>
#define fir first
#define sec second
#define ll long long
using namespace std;
const int N=2510;
int n,m,k;
bool g1[N][N];ll g[N][N];
ll f[N][3],w[N];
PII q[N];bool st[N];
bool ok(int x,int y){
return g[x][y]<=k+1;
}
void Bfs(int sta){
memset(st,0,sizeof(st));
int hh=0,tt=-1;
q[++tt]={sta,0};
while(hh<=tt){
PII t=q[hh++];
int ver=t.fir,dis=t.sec;
if(dis>k) break;
if(st[ver]) continue;
st[ver]=1;
for(int i=1;i<=n;i++)
if(g1[ver][i]&&!st[i]){
g[sta][i]=dis+1;
q[++tt]={i,dis+1};
if(sta==1||!ok(1,i)) continue;
if(i!=1&&w[i]>=w[f[sta][0]]) f[sta][2]=f[sta][1],f[sta][1]=f[sta][0],f[sta][0]=i;
else if(i!=1&&w[i]>=w[f[sta][1]]) f[sta][2]=f[sta][1],f[sta][1]=i;
else if(i!=1&&w[i]>w[f[sta][2]]) f[sta][2]=i;
}
}
}
signed main(){
memset(g,0x3f,sizeof(g));
scanf("%d%d%d",&n,&m,&k);
for(int i=2;i<=n;i++) scanf("%lld",&w[i]);
w[0]=-1e18;
while(m--){
int a,b;scanf("%d%d",&a,&b);
g1[a][b]=g1[b][a]=1;
}
for(int i=1;i<=n;i++) Bfs(i);
ll ans=0;
for(int i=2;i<=n;i++)
for(int j=2;j<=n;j++){
if(i==j||!ok(i,j)) continue;
for(int c1=0;c1<3;c1++)
for(int c2=0;c2<3;c2++){
if(f[i][c1]!=j&&f[j][c2]!=i&&f[i][c1]!=f[j][c2]&&f[i][c1]!=i&&f[j][c2]!=j)
ans=max(ans,w[i]+w[j]+w[f[i][c1]]+w[f[j][c2]]);
}
}
printf("%lld",ans);
return 0;
}