P2904 [USACO08MAR] River Crossing S题解

整体思路分析:

这一题可以用背包的思路来做——。

首先,设 f [ j ] 表示载 j 头奶牛过河的最小时间,sum[ i ]表示一次载 i 头奶牛过河的时间,那么状态转移方程就是:

f[j]=min(f[j],f[j-i]+sum[i])

最后输出f[n]

这个方程是什么意思呢?

首先,f[ j−i ]+sum[ i ]f[ j−i ]+sum[ i ]就是代表少载ii头奶牛再加上载ii头奶牛的时间,与原来算出来的f[ j ]f[ j ]比较,看一下哪一个比较少。

ii从1−n1−n循环,jj从i−ni−n循环。

那么sum[ i ]sum[ i ]要怎么计算呢?我们用前缀和:

sum[ i ]=sum[ i−1 ]+w[ i ] (w[ i ]为题目中的Mi)sum[ i ]=sum[ i−1 ]+w[ i ] (w[ i ]为题目中的Mi)

如果理解不来,你可以这样想:

把ii当成完全背包的重量,sum[ i ]sum[ i ]当成价值,然后求最小价值。

然后每个sum[ i ]sum[ i ]加上2m2m,就是筏子一次来回的时间,最后输出的时候再减去mm,因为最后一次不用划回来。

注释代码:

#include<iostream>
#include<cstdio>
using namespace std;
int f[10010];
int sum[10010];
int w[10010];
int m,n;
const int inf=99999999;
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		f[i]=inf;//要求最小值的话,每一个f[i]都要赋值为无限大。
		cin>>w[i];
		sum[i]=sum[i-1]+w[i];//计算前缀和。
	}
	for(int i=1;i<=n;i++){
		sum[i]+=2*m;
	}//每个加上2*m
	for(int i=1;i<=n;i++){
		for(int j=i;j<=n;j++){
			f[j]=min(f[j],f[j-i]+sum[i]);//方程,和背包差不多
		}
	}
	cout<<f[n]-m;//输出的时候减掉m,因为不用划回来。
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值