CSP-S 2022 T1题解

题目描述 :

在一张图中找到能够到达的四个点,使之点权之和最大。

先说说考场上的思路吧,要求不超过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;
}
posted @ 2022-10-31 08:02  别说我高冷哦  阅读(145)  评论(0)    收藏  举报