线性dp [USACO08MAR]River Crossing S(洛谷 P2904)

[USACO08MAR]River Crossing S

题目描述

Farmer John is herding his N cows (1 <= N <= 2,500) across the expanses of his farm when he finds himself blocked by a river. A single raft is available for transportation.

FJ knows that he must ride on the raft for all crossings and that that adding cows to the raft makes it traverse the river more slowly.

When FJ is on the raft alone, it can cross the river in M minutes (1 <= M <= 1000). When the i cows are added, it takes M_i minutes (1 <= M_i <= 1000) longer to cross the river than with i-1 cows (i.e., total M+M_1 minutes with one cow, M+M_1+M_2 with two, etc.). Determine the minimum time it takes for Farmer John to get all of the cows across the river (including time returning to get more cows).

Farmer John以及他的N(1 <= N <= 2,500)头奶牛打算过一条河,但他们所有的渡河工具,仅仅是一个木筏。 由于奶牛不会划船,在整个渡河过程中,FJ必须始终在木筏上。在这个基础上,木筏上的奶牛数目每增加1,FJ把木筏划到对岸就得花更多的时间。 当FJ一个人坐在木筏上,他把木筏划到对岸需要M(1 <= M <= 1000)分钟。当木筏搭载的奶牛数目从i-1增加到i时,FJ得多花M_i(1 <= M_i <= 1000)分钟才能把木筏划过河(也就是说,船上有1头奶牛时,FJ得花M+M_1分钟渡河;船上有2头奶牛时,时间就变成M+M_1+M_2分钟。后面的依此类推)。那么,FJ最少要花多少时间,才能把所有奶牛带到对岸呢?当然,这个时间得包括FJ一个人把木筏从对岸划回来接下一批的奶牛的时间。

输入格式

  • Line 1: Two space-separated integers: N and M

  • Lines 2…N+1: Line i+1 contains a single integer: M_i

输出格式

  • Line 1: The minimum time it takes for Farmer John to get all of the cows across the river.

题目刚开始没有看清楚,一直没明白样例,最后发现每次过河运牛所花的时间是M_1,M_2,而不是M_i;

这题刚开始想就是:dp[i][j]=min(dp[i][j],dp[i-1][j-k]+sum[k]+2*m);

表示前 i 趟,运了 j 头牛的最小时间,然后发现复杂度为n^3,交上去60分;

最后观察发现,第几趟并不重要,可以删去,并且复杂度降了一维,空间也降了一维;

这道题的最大的收获就是这种推理过程,以及适当的优化;

代码:

#include<bits/stdc++.h>
#define LL long long
#define pa pair<int,int>
#define ls k<<1
#define rs k<<1|1
#define inf 0x3f3f3f3f
using namespace std;
const int N=3000;
const int M=2000100;
const LL mod=1e8;
int dp[N],sum[N];
int main(){
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>sum[i],sum[i]+=sum[i-1];
	for(int i=1;i<=n;i++) dp[i]=2e9;
	dp[0]=0;
	for(int i=1;i<=n;i++){
		for(int j=0;j<=i;j++){
			dp[i]=min(dp[i],dp[i-j]+sum[j]+2*m);
		}
	}
	cout<<dp[n]-m<<endl;
	return 0;
}

60分代码:

#include<bits/stdc++.h>
#define LL long long
#define pa pair<int,int>
#define ls k<<1
#define rs k<<1|1
#define inf 0x3f3f3f3f
using namespace std;
const int N=3000;
const int M=2000100;
const LL mod=1e8;
int dp[N][N],sum[N];
int main(){
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>sum[i],sum[i]+=sum[i-1];
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++) dp[i][j]=2e9;
	}
	dp[0][0]=0;
	for(int i=1;i<=n;i++){
		for(int j=0;j<=n;j++){
			for(int k=0;k<=j;k++){
				dp[i][j]=min(dp[i][j],dp[i-1][j-k]+sum[k]+2*m);
			}
		}
	} 
	cout<<dp[n][n]-m<<endl;
	return 0;
}
发布了264 篇原创文章 · 获赞 46 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_44291254/article/details/105295050