火车头——思路与题解

引子:

为什么要写这道题呢?这道题虽然简单,但是我觉得我想写屁话!,因为这道题呢,有一些细节真的是值得我们去关注的。


题目

思路:

因为是要求可以拉最大的人数,而且必须是连续且从走往右的所以,这道题的大体可以往最长上升子序列那边思路想。
所以状态转移方程应该是:

  dp[i][j] = max(dp[i][j - 1],dp[i - 1][j - m] +b[j] - b[j - m]);

这个方程的意思是在第i个车头时可以拉j个车厢。

注意有一个细节!第一层循环是枚举车头的数量

for(int i=1;i<=3;i++)

第二层循环呢是枚举,在第i火车头时,拉m个车厢能拉的最多人

for(int j=m;j<=n;j++)

问题来了:为什么j要从m开始呢?

因为题目告诉了啊>_<

一个正整数m,代表能够被单一火车头拉动的最大火车厢个数

那么为什么j<=n呢?

因为题目也告诉了啊>_<

所以目标就是在当第三个车头的时候拉n个车厢才能保证拉的人数最多。

所以最后输出应该是

printf("%d\n",dp[3][n]);

代码:

//QAQ
#include
#include 
#include
using namespace std;
int dp[5][50005],a[50005],b[50005];
int max(int x,int y){
    if (x>y) return x;
    else return y;
}
int main(){
	int m,t,n;
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		for(int i=1;i<=n;i++){
			scanf("%d",&a[i]);
			b[i]=b[i-1]+a[i];
		}
		scanf("%d",&m);
		for(int i=1;i<=3;i++){//枚举第i个火车头 
			for(int j=m;j<=n;j++){ //第i火车头时,必须拉m个来能拉最多人(3*m<=n) 
				dp[i][j] = dp[i][j - 1];
                dp[i][j] = max(dp[i][j - 1],dp[i - 1][j - m] +b[j] - b[j - m]);
			}
		}
		printf("%d\n",dp[3][n]);
	}
	return 0;
} 

还有一些细节,因为本人能力的问题也不知道该怎么说出来。

所以,还有什么不懂可以问一问本人。就这样吧。

你可能感兴趣的:(DP,01背包)