整体思路分析:
这一题可以用背包的思路来做——。
首先,设 f [ j ] 表示载 j 头奶牛过河的最小时间,sum[ i ]表示一次载 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;
}