HOJ——Baking Cakes 学习DP4

Baking Cakes


Tom's birthday is coming up, and you have been put in charge of baking cakes for his monstrous birthdayparty. However, you have a great number of cakes to make, and a very short amount of time, so you are notsure that you will even finish before the party!

You have a list of different cakes to make, each requiring a certain amount of time to bake. You alsohave exactly 3 ovens to bake the cakes in, and each oven can only bake one cake at a time. Assuming thatthe time required to take a cake out and put another one in is negligible, can you determine the smallestamount of time you will need to spend baking, given the list of cakes to make?

Input

The input test file will contain multiple cases, with each case on a single line. The line begins with an integern(1 ≤ n ≤ 40), the number of cakes to bake. Following are n integers, t1, ... , tn(1 ≤ ti ≤ 30),indicating the time in minutes required to bake each of your cakes. End-of-input is marked by a single linecontaining 0; do not process this line.

Output

For each test case, output on a single line the smallest amount of time, in minutes, that you need to bakeall of your cakes.

Sample Input

1 30
3 15 10 20
5 6 7 8 9 10
0

Sample Output

30
20
15
 

这个问题困扰我两年了,之所以注意它是因为感觉很有使用价值,属于任务调度问题。首先想着贪心,很明显贪心连测试用力都过不了,最近感觉是个DP

,关键是不知道动机。刚做完多校联合7的比赛,有一题概率DP对我的启发很大,此题大体上也是相同的思路。确定维度的选取,关键是降低复杂度。此题

dp[i][j]分别i代表1号拷机总的时间,j代表2号拷机总的时间。我们只需记录下总体时间减去前两个即是第三个拷机烤的时间即:sum-i-j。

为何如此选取呢?n<=40,t<=30,一共也不会超出1200,二维才100多万,时间复杂度是允许的,实际上给出数据范围的目的 也在于此,直观

枚举共2^40的复杂度,根本不可取,实际上由于数据范围的限定会有很多是重复的。前后状态的转移还是有一定技巧的。

代码如下:

/*
 * File:   main.cpp
 * Author: hit-acm
 *
 * Created on 2012年5月2日, 下午5:19
 */

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
const int MAX = 30 * 40 + 1;
const int INF = 0x7fffffff;
bool color[MAX][MAX];

int main() {
    int n, t;
    while (scanf("%d", &n) && n) {
        memset(color, 0, sizeof (color));
        color[0][0] = true;
        int sum = 0;
        while (n--) {
            scanf("%d", &t);
            for (int i = sum; i >= 0; i--) {
                for (int j = sum; j >= 0; j--) {
                    if (color[i][j]) {
                        color[i + t][j] = color[i][j + t] = true;
                    }
                }
            }
            sum += t;
        }
        int ans = INF;
        for (int i = 0; i <= sum; i++) {
            for (int j = 0; j <= sum; j++) {
                if (color[i][j]) {
                    ans = min(ans, max(max(i, j), sum - i - j));
                }
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}

学习DP继续努力!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值