牛客网:牛牛送冰淇淋

链接:https://ac.nowcoder.com/acm/contest/6630/C
来源:牛客网

牛牛公司老板让牛牛负责m个冰激凌的运输。运输车的冷库只够装n个冰激凌,一次运输需要t分钟,返回也需要t分钟。每个冰激凌制作好有一个时间。牛牛想知道最短运输完所有冰激凌的时间,以及在时间最短的情况下最少运输次数。
示例1
输入

2,3,10,[10,30,40]

输出

[50,2]
备注:
(1≤n,m,t≤2000)

思路:
动态规划,本题的关键在于如何将问题抽象到动态规划模型之中,即如何利用动态规划的解题思路来理解题目。
1. 确定状态。对于题目来说,需要求两个最优的值,而比较迷惑的是,对于最少运输次数而言,与运送时间最短的关系并不相关。换句话说,对于取得最短运送时间的运送次数,一定是所有运送方案中运送次数最少的。证明如下:对于n号冰激凌来说,要完成它的运送至少是在n+t的时间完成,那么在这之前,不可能存在一种方案能够使得这个时间提前,也就是说在这之前的最少的方案就是贪心的运送方案。因此使用两个dp数组:dp[]和ctimes[]分别记录最短时间和最少次数。
2. 写到这儿发现并不需要动态规划,n个一车拉就完事了;
3. 但是还是把动态规划的思路写完,确定状态转移方程,对于最短时间来说,dp[i]应该是等于,dp[i] = min(dp[i],max(dp[j]+t,c[i])+t);怎么理解呢,就是在之前的i之前的n个(存在一车一起拉走的可能性),n个他们送完之后再送i和他们等着i一起送这两者之间较大的,这n个中的最小值。
4. 确认初始值。dp[0]原本应该等于0,但是在本题中,根据递推公式来说,dp[1]如果需要等于c[1]+t,那么dp[0]+t就一定需要小于c[1]。所以dp[0]=-t(理论上小于-t也可以)。ctimes[0]=0,ctimes[1]=1。

动态规划方法

class Solution {
public:
    /**
     * 两个数表示答案
     * @param n int整型 一次运输的冰激凌数量
     * @param m int整型 总冰激凌数
     * @param t int整型 一次运输的时间
     * @param c int整型一维数组 表示每个冰激凌制作好时间<1e4
     * @param cLen int c数组长度
     * @return int整型vector
     */

    vector<int> icecream(int n, int m, int t, int* c, int cLen) {
        
        vector<int> dp(2020,INT_MAX);
        vector<int> ctimes(2020,INT_MAX);
        // write code here
        sort(c,c+cLen);
        for(int i=cLen;i>=1;i--)
        {
            c[i] = c[i-1];
        }
        c[0]=0;
        dp[0] = -t;
        ctimes[0]=0;
        ctimes[1]=1;
        
        for(int i = 1;i<=m;i++)
        {
            for(int j = max(0,i-n);j<i;j++)
            {
                dp[i] = min(dp[i],max(dp[j]+t,c[i])+t);
                ctimes[i] = min(ctimes[j]+1,ctimes[i]);
            }
        }
        
        return {dp[m],ctimes[m]};
    }
};

贪心方法:

class Solution {
public:
    /**
     * 两个数表示答案
     * @param n int整型 一次运输的冰激凌数量
     * @param m int整型 总冰激凌数
     * @param t int整型 一次运输的时间
     * @param c int整型一维数组 表示每个冰激凌制作好时间<1e4
     * @param cLen int c数组长度
     * @return int整型vector
     */

    vector<int> icecream(int n, int m, int t, int* c, int cLen) {

        // write code here
        sort(c,c+cLen);
        
        int ans = -t;
        int start = (m%n)?(m%n):n;
        for(int i = start-1;i<m;i+=n)
        {
            ans+=t;
            ans  = max(c[i],ans);
            ans+=t;
        }
        
        
        return {ans,m/n+((m%n)!=0)};
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值