题目描述 :
在一张图中找到能够到达的四个点,使之点权之和最大。
先说说考场上的思路吧,要求不超过k次转车,其实就是要求长度不超过k。所以只需要找出这张图的全源最短路,然后建好新图,在新图里直接跑dfs求解。
但是没有想出合适的求全源最短路的算法,直接跑了floyd,而且没有剪枝操作,时间复杂度很高。而且没开long long 部分分也没拿到。
现在补上T1的正解:
对于每个点,只要能在k次搜索前搜到,就一定能到达,所以直接bfs搜索,n^2建好新图,跑dfs,对于每个点,如果从1号点走x步到达该点,如果此时状态不是最优的,答案一定不会被更新。换句话说,从1号点出发,走到该点的权值总和要最大,才能求出最优解。
代码奉上:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 1e4 + 100;
int n, m, k;
int dis[2510][2510];
ll ans;
bool vis[N];
ll w[N], d[N][5];
vector<int>q1[2520], q2[2520];
void bfs(int s){
queue<int>q;
q.push(s);
dis[s][s] = 0;
while(q.size()){
int x = q.front();
q.pop();
if(dis[s][x] > k + 1) return ;
if(dis[s][x] <= k + 1) q2[s].push_back(x);
for(int i = 0;i < q1[x].size();i ++){
int u = q1[x][i];
if(dis[s][u] == 0x3f3f3f3f){
dis[s][u] = dis[s][x] + 1;
q.push(u);
}
}
}
}
void dfs(int x, int dep, ll sum){
if(sum <= d[x][dep]) return;
d[x][dep] = sum;
if(dep == 4){
if(x != 1 && dis[1][x] <= k + 1) ans = max(ans, sum);
return;
}
for(int i = 0;i < q2[x].size();i ++){
int u = q2[x][i];
if(vis[u] || u == 1) continue;
vis[u] = 1;
dfs(u, dep + 1, sum + w[u]);
vis[u] = 0;
}
}
int main(){
scanf("%d%d%d", &n, &m, &k);
for(int i = 2;i <= n;i ++){
scanf("%lld", &w[i]);
}
for(int i = 1;i <= m;i ++){
int a, b;
scanf("%d%d", &a, &b);
q1[a].push_back(b);
q1[b].push_back(a);
}
memset(dis, 0x3f, sizeof dis);
for(int i = 1;i <= n;i ++){
bfs(i);
}
memset(vis, 0, sizeof vis);
memset(d, -0x3f, sizeof d);
dfs(1, 0, 0);
cout << ans << "\n";
return 0;
}
标签:int,题解,ll,long,T1,2022,CSP,dis
From: https://www.cnblogs.com/dzdyshenqing/p/16843007.html