[Leaf] [ZJ2021J] Grammy and Jewelry

zj2021j---grammy-and-jewelry">ZJ2021J - Grammy and Jewelry

1. 题面梗概

中译中: 图上有 nn 个点,你在 1 号点,第 ii 有无限个价值为 aia_i 的珠宝。你每次只能搬一个,搬运过程:1→i→11 \to i \to 1。每条边走 1 分钟。问在 1…T1 \dots T 分钟内,每个时间点能拿到的最大总价值是多少。

2. 逻辑推导

第一反应是背包问题,同时还是完全背包,无限物品,价值,成本,都在暗示。

既然每条边的边权相等,那么我们可以直接用 BFSBFS 预处理最短路(也就是成本)。

然后完全背包 DP,即可算出答案。

定义:dp[j]dp[j] 表示 jj 时间内能获得的最高价值。

转移:dp[j]=max⁡(dp[j],dp[j−2di]+ai)dp[j] = \max(dp[j], dp[j - 2d_i] + a_i)。

3. 代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using PII = pair<int, int>;

const int maxn = 3e3 + 5;

vector< int > adj[maxn];
int dist[maxn];
int a[maxn];
ll dp[maxn];
int n, m, T;

void bfs( int start )
{
queue< int > q;
q.push( start );
dist[1] = 0;

while( !q.empty( ) )
{
int u = q.front( );
q.pop( );

for( int v : adj[u] )
{
if( dist[v] == -1 )
{
dist[v] = dist[u] + 1;
q.push( v );
}
}
}
}

void solve( )
{
cin >> n >> m >> T;
for( int i = 2; i <= n; ++ i )
{
cin >> a[i];
}

for( int i = 1; i <= m; ++ i )
{
int u, v;
cin >> u >> v;
adj[u].push_back(v);
adj[v].push_back(u);
}

memset( dist, -1, sizeof( dist ) );

bfs( 1 );

for( int i = 2; i <= n; ++ i )
{
if( dist[i] == -1 ) continue;
for( int j = 2 * dist[i]; j <= T; ++ j )
{
dp[j] = max( dp[j], dp[j - 2 * dist[i]] + a[i] );
}
}

for( int k = 1; k <= T; ++ k )
{
cout << dp[k] << " ";
}
cout << '\n';
}

int main( )
{
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int _t = 1;
// cin >> _t;
while( _t -- )
{
solve( );
}
return 0;
}

4. 复盘

  • 复杂度: O(N+M+N×T)O( N + M + N \times T )

  • 碎碎念: 其实不难,只要能理解广义背包的概念,选与不选,这题就简单地化解为完全背包模型,只需要跑一遍 BFS 即可。

  • 关联笔记: 背包DP


[Leaf] [ZJ2021J] Grammy and Jewelry
http://miqiu.space/posts/289904fa/
作者
Miqiu
发布于
2026年1月22日
许可协议