📝

E2-G

Importance
📙📙📙
Start Date
Sep 19, 2023
tags
Dynamic Programming
Simulation
notion image

题目要求

你初始时刻位于坐标原点,每个时间周期只能往上下左右四个方向移动一个单位。给定每个金币的出现坐标与时刻(当且仅当你在这个时刻位于这个坐标上时你能获得这个金币),求你能获得的最大金币数。
 

核心算法和原理

  • 首先将所有金币按照时间顺序排序,这样得到了一个确定的金币序列c。
  • 你能同时获得两个金币i, j (i < j)的条件是:c[i] 与 c[j]的(Δx + Δy) ≤ Δt(即保证你用最短时间从i金币走到j金币的位置之前j金币没有出现)。
  • 可以想到线性DP思路:
    • dp数组定义:dp[i]为拿到c[i]的情况下最多能拿到的金币数(i ≥1)。
    • 基态:dp[0] = 0,表示什么都不拿的初态。dp[i] = -1,表示拿不到c[i]或者还没开始拿c[i]。
    • 状态转移方程:dp[i+1] = max(dp[j] + 1) ( j < i && 满足上述条件 && dp[j] > 0(即c[j]是可以被拿到的) )。
  • 结果表示: max(dp[i])(i 属于 1 ~ n)

代码

#include <bits/stdc++.h> using namespace std; struct coin{ int x; int y; int t; }c[2001]; int dp[2001]; bool cmp(coin a, coin b); bool judge(int j, int i); int main(){ ios::sync_with_stdio(false); cin.tie(0); int tt; int n; cin >> tt; while(tt--){ cin >> n; for(int i = 1; i <= n; i++){ cin >> c[i].x >> c[i].y >> c[i].t; } sort(c + 1, c + n + 1, cmp); coin pos; pos.x = pos.y = pos.t = 0; c[0] = pos; dp[0] = 0; int ans = 0; for(int i = 1; i <= n; i++) { dp[i] = -1; for (int j = 0; j < i; j++) { if (dp[j] != -1 && dp[i] < dp[j] + 1 && judge(j, i)) { dp[i] = dp[j] + 1; } } ans = max(dp[i], ans); } cout << ans << endl; } return 0; } bool cmp(coin a, coin b){ return a.t < b.t; } bool judge(int j, int i){ return (abs(c[i].x - c[j].x) + abs(c[i].y - c[j].y)) <= c[i].t - c[j].t; }