1 条题解

  • 0
    @ 2025-8-24 21:43:17

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Yanzy2333
    咸鱼一条。

    搬运于2025-08-24 21:43:17,当前版本为作者最后更新于2018-12-15 16:09:18,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    这一题可以用背包的思路来做(这就是为什么这一题的标签有个背包)。

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

    $$f[\ j\ ]=min(f[\ j\ ],f[\ j-i\ ]+sum[\ i\ ])\text{,最后输出f[\ n\ ]} $$

    这个方程是什么意思呢?

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

    ii1n1 - n循环,jjini-n循环。

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

    $$sum[\ i\ ]=sum[\ i-1\ ]+w[\ i\ ]\text{ (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;
    }
    

    题外话(如果你没时间的话,不看也没关系):

    这里附加一个LaTeX\LaTeX公式小窍门:

    在表示数组的时候,一般用

    $f[i]$
    

    f[i]f[i]

    这样就会贴在一起,不好看。可以加一个空格(LaTeX\LaTeX中空格是右斜杠+空格)

    $f[\ i\ ]$
    

    f[ i ]f[\ i\ ]

    你还可以自行调整

    $f[\,i\,]$
    $f[\;i\;]$
    

    f[i]f[\,i\,]

    f[  i  ]f[\;i\;]

    当然如果你喜欢原来的样子也可以的。

    或者是

    $f_i$
    

    fif_i


    • 1

    信息

    ID
    1969
    时间
    1000ms
    内存
    125MiB
    难度
    3
    标签
    递交数
    0
    已通过
    0
    上传者