其他分享
首页 > 其他分享> > 2021年五月六日中午训练

2021年五月六日中午训练

作者:互联网

最近在做中午练习时发现一道很妙的题,叫做"火车头"。

题目描述

宏帆八中有一个火车站,里面有3个火车头和n个火车厢,每个火车厢里面对应的有一定的人数。规定每个火车头最多拉m个连续的火车厢而且他们拉的车厢一定是从左到右连续的,问它能够拉的最多的人数;

输入格式

第一行:一个整数T(1 <= t <= 11),代表测试样例个数。

接下来T组测试数据:

第一行:一个正整数n,代表火车厢个数,(n <= 50000)

第二行:n个正整数,分别表示第i个火车厢能装的人的个数(均不超过100)

第三行:一个正整数m,代表能够被单一火车头拉动的最大火车厢个数(<= n / 3)

输出格式

一个正整数,代表能够被3个火车头拉动的最大的人数。

样例

样例输入
1

7

35 40 50 10 30 45 60

2

样例输出

240

思路

错误思路

贪心

拿到这个题,我第一时间想到了贪心,用一个ans数组来存储m个和的最大值,然后依次按最大的选,但我们发现:排序就会影响原本的顺序,也有可能会选重复。又因为这道题是一道动态规划的题,所以只能用动态规划做。

正确思路

动态规划

当然,我们也必须要用一个ans数组来存储m个和的最大值。
顺带一提,我最开始求ans数组是用的O( n 2 n^2 n2)(两层循环)做的,但可以用一个专门求区间和的东西来优化,就是前缀和

前缀和公式

sum[i] = sum[i - 1] + a[i]

接下来我们定义状态
dp[i][j]:表示前i个车厢进入j个区间能装载的总人数
转移我们就抓住i项选不选
若选
那么i - x + 1项也会选
即dp[i][j] = dp[i - x][j - 1] + ans[i - x + 1]
若不选
那么dp[i][j] = dp[i - 1][j]

代码

#include<bits/stdc++.h>
using namespace std;
long long T,n,a[50005],x,dp[50005][4],ans[50005],sum[50005];
int main(){
	cin >> T;
	while(T--){
		memset(ans,0,sizeof(ans));//初始化
		memset(dp,0,sizeof(dp));//初始化
		memset(sum,0,sizeof(sum)); //初始化
		cin >> n;
		for(int i = 1;i <= n;i++){
			cin >> a[i];
			sum[i] = sum[i - 1] + a[i]; //前缀和
		}
		cin >> x;
		for(int i = 1;i <= n - x + 1;i++){
			ans[i] = sum[i + x - 1]  - sum[i - 1];//求出连续x个的值
		}
		for(int i = x;i <= n;i++){
			for(int j = 1;j <= 3;j++){
				dp[i][j] = max(dp[i - 1][j],dp[i - x][j - 1] + ans[i - x + 1]); //状态转移
		}
		} 
		cout << dp[n][3] << endl;
	}
	return 0;
} 

今天就和大家分享到这里,大家再见!!!

标签:六日,火车头,int,sum,车厢,2021,五月,ans,dp
来源: https://blog.csdn.net/xuyuetan/article/details/116464115