#include using namespace std; const int N = 1e3 + 10; /* 视频讲解 https://www.bilibili.com/video/BV1iT4y1U7tV/?spm_id_from=333.999.0.0 经验总结: 1、从样例入手,通过简单样例,思考人脑思维是如何一点点解决问题的。 2、在模拟样例的过程中,我们其实也是在秉承 多层循环,分别讨论的思路进行的思考。 3、在模拟样例的过程中,我们会发现有些地方是需要特判的,比如环形在1号与n号的交界处等情况,需要 road-=n 4、本题的题意是在任意时刻,你可以终止上一个机器人,它不用走完p个时长。 同时,下一个工厂也不一定非得是现在机器人停止的位置,可以是任意一个。这样自由度就很大,在代码中起到了降维的作用,否则 你就还需要考虑停止的位置,也就是下一个启动的工厂,是不是一定是前一个最大值的停止位,这样就不是一维的f[N]可以描述的了 最开始,我就是卡在这里,认为题解是错误的。 5、画图+样例梳理是解决问题的关键,先用人脑解决掉测试样例是非常重要的办法,然后再用代码模拟实现,再然后才是优化。 */ int gold[N][N]; // gold[i][j]:第i条路,第j个时刻,可以获得的金币数量 int cost[N]; // cost[i]:在i个工厂购买机器人的花费 int n, m, p; // n个工厂,m个单位时间,p:机器人行走次数的上限 int f[N]; // f[i]:在前i个时间内,可以获得的最多金币数量 int main() { cin >> n >> m >> p; // 工厂数量,最长的时长,机器人可以行走的次数上限 for (int i = 1; i <= n; i++) // n个工厂,比如2个工厂,其实有两条路径 ,就是1->2,2->1,工厂数量也就是路径数量 for (int j = 1; j <= m; j++) // m个时长 cin >> gold[i][j]; // 每段路径,在每个单位时间,可以获取到的金币数量 for (int i = 1; i <= n; i++) cin >> cost[i]; // 在每个工厂购买机器人需要花费的金币数量 // !!!!!!注意!!!!!! // 有效状态初始化为负无穷,不能i=0开始,因为下面的代码中会依赖i=0,i=0时f[i]=0 for (int i = 1; i <= m; i++) f[i] = -1e9; for (int i = 1; i <= m; i++) { // 枚举每个单位时间 for (int j = 1; j <= n; j++) { // 枚举每个工厂 int tmp = f[i - 1] - cost[j]; // 上一个时间单元的最大值,减去在j这个工厂购买机器人的花费金币数 for (int k = 0; k < p && i + k <= m; k++) { int road = j + k; // 从j这个工厂开始,走k步(已减1),是哪个道路,比如:从1号工厂,走0步,就是1号道路 int time = i + k; // 到达了哪一时刻 if (road > n) road = road - n; // 环形 tmp += gold[road][time]; // 加上此道路,此时刻捡起来的金币数 f[time] = max(f[time], tmp); // 不断取最大值 } } } // 输出 printf("%d\n", f[m]); return 0; }