思路是先处理出每个点能否在 k 步内到达其他点,然后将处理出来的东西转化为 n 个集合,分别表示每个点能在 k 步内到达的点集。
然后接一个带了优化的 O(n4) dfs 用来枚举 A,B,C,D,dist[u][st] 表示从家出发到 u 点,并将 u 点作为第 st 个景点(A,B,C,D)的最大分数之和。
fg[i] 是能否从家出发在 k 步内到达 i,在 dfs 时使用,便于 O(1) 判断从当前点能否到达家,从而更新答案
#include <iostream>
using namespace std;
typedef long long ll;
template<typename T=ll>
inline T read(){
T X=0; bool flag=1; char ch=getchar();
while(ch<'0' || ch>'9'){if(ch=='-') flag=0; ch=getchar();}
while(ch>='0' && ch<='9') X=(X<<1)+(X<<3)+(ch^48),ch=getchar();
if(flag) return X;
return ~(X-1);
}
const int N=3e3+5,M=1e4+5,K=1e2+5,inf=0x3f3f3f3f;
struct edge{
int to,nxt;
}e[M<<1];
int n,m,k,u,v;
ll val[N],ans;
int head[N],top;
int g[N][N],sz[N],fg[N];
ll dist[N][5],vis[N];
struct node{int u,k;}q[N*M];
int l,r;
void add(int u,int v){
top++;
e[top].to=v;
e[top].nxt=head[u];
head[u]=top;
}
void bfs(int i){
r=0;
q[++r]={i,0};
l=1;
while(l<=r){
int u=q[l].u,x=q[l].k;
l++;
if(x++>k+1) break;
if(g[i][u]) continue;
g[i][u]=1;
for(int h=head[u]; h; h=e[h].nxt){
v=e[h].to;
if(!g[i][v]) q[++r]={v,x};
}
}
}
void dfs(int u,int st,ll w){
if(st==4){
if(fg[u]) ans=max(ans,w);
return;
}
if(w<dist[u][st]) return;
dist[u][st]=w;
for(int i=1; i<=sz[u]; i++){
if(vis[g[u][i]]) continue;
vis[g[u][i]]=1;
dfs(g[u][i],st+1,w+val[g[u][i]]);
vis[g[u][i]]=0;
}
}
int main(){
n=read(),m=read(),k=read();
for(int i=2; i<=n; i++) val[i]=read();
while(m--){
u=read(),v=read();
add(u,v),add(v,u);
}
for(int i=1; i<=n; i++) bfs(i);
for(int i=1; i<=n; i++) g[i][i]=0;
for(int i=1; i<=n; i++) if(g[i][1]) fg[i]=1;
for(int i=1; i<=n; i++)
for(int j=2; j<=n; j++)
if(g[i][j])
g[i][++sz[i]]=j;
dfs(1,0,0);
printf("%lld\n",ans);
return 0;
}