【题解】SHOI2001化工厂装箱员

————传送:洛谷P2530

这道题目还是挺简单的,状态也容易想到。

数据范围非常的小,所以即便是很多维度,复杂度也完全可以接受。定义状态:dp[i][a][b][c]为手上的货物拿到第i个时三种物品分别有a, b, c个所用的最少次数。

状态转移就暴力枚举是放下a,b,c中的哪一个。

只不过需要特判一下n<10的情况。//再一次对自己丑陋的代码有点接受无能……

#include <bits/stdc++.h>
using namespace std;
#define maxn 102
#define INF 999999
int n, ans = INF, suma[maxn], sumb[maxn], sumc[maxn], dp[maxn][11][11][11];
char c[maxn];

int min(int a, int b)
{
    if(b == -1) return a;
    if(a == -1) return b;
    return a < b ? a : b;
}

int trans(int x, int y, int aa, int bb, int cc)
{
    int a = suma[y] - suma[x], b = sumb[y] - sumb[x], c = sumc[y] - sumc[x];
    int sum = a + b + c + aa + bb + cc;
    bool done = false;
    if(sum - aa <= 10) done = true, dp[y][a][b + bb][c + cc] = min(dp[x][aa][bb][cc] + 1, dp[y][a][b + bb][c + cc]);
    if(sum - bb <= 10) done = true, dp[y][a + aa][b][c + cc] = min(dp[x][aa][bb][cc] + 1, dp[y][a + aa][b][c + cc]);
    if(sum - cc <= 10) done = true, dp[y][a + aa][b + bb][c] = min(dp[x][aa][bb][cc] + 1, dp[y][a + aa][b + bb][c]);
    if(!done) return -1;
    else return 0;
}

int main()
{
    scanf("%d\n", &n);
    memset(dp, -1, sizeof(dp));
    for(int i = 1; i <= n; i ++)
    {
        cin >> c[i];
        suma[i] = suma[i - 1];
        sumb[i] = sumb[i - 1];
        sumc[i] = sumc[i - 1];
        if(c[i] == ‘A‘) suma[i] ++;
        else if(c[i] == ‘B‘) sumb[i] ++;
        else sumc[i] ++;
    }
    if(n < 10)//特判
    {
        ans = 0;
        if(suma[n]) ans ++;
        if(sumb[n]) ans ++;
        if(sumc[n]) ans ++;
        printf("%d\n", ans);
        return 0;
    }
    dp[10][suma[10]][sumb[10]][sumc[10]] = 0;
    for(int i = 10; i <= n; i ++)
    {
        for(int aa = 0; aa <= 10; aa ++)
            for(int bb = 0; bb <= 10; bb ++)
                for(int cc = 0; cc <= 10; cc ++)
                {
                    if(dp[i][aa][bb][cc] == -1) continue;
                    for(int j = i + 1; j <= n; j ++)
                        if(trans(i, j, aa, bb, cc) == -1) break;
                }
    }
    for(int aa = 0; aa <= 10; aa ++)
        for(int bb = 0; bb <= 10; bb ++)
            for(int cc = 0; cc <= 10; cc ++)
            {
                if(dp[n][aa][bb][cc] == -1) continue;
                int tem = 0;
                if(aa) tem ++;
                if(bb) tem ++;
                if(cc) tem ++;
                ans = min(ans, dp[n][aa][bb][cc] + tem);
            }
    printf("%d\n", ans);
    return 0;
}

原文地址:https://www.cnblogs.com/twilight-sx/p/8408696.html

时间: 2024-10-14 08:45:35

【题解】SHOI2001化工厂装箱员的相关文章

搜索 洛谷P2530 [SHOI2001]化工厂装箱员

P2530 [SHOI2001]化工厂装箱员 题目描述 118号工厂是世界唯一秘密提炼锎的化工厂,由于提炼锎的难度非常高,技术不是十分完善,所以工厂生产的锎成品可能会有3种不同的纯度,A:100%,B:1%,C:0.01%,为了出售方便,必须把不同纯度的成品分开装箱,装箱员grant第1次顺序从流水线上取10个成品(如果一共不足10个,则全部取出),以后每一次把手中某种纯度的成品放进相应的箱子,然后再从流水线上顺序取一些成品,使手中保持10个成品(如果把剩下的全部取出不足10个,则全部取出)

洛谷P2530 [SHOI2001]化工厂装箱员

题目描述 118号工厂是世界唯一秘密提炼锎的化工厂,由于提炼锎的难度非常高,技术不是十分完善,所以工厂生产的锎成品可能会有3种不同的纯度,A:100%,B:1%,C:0.01%,为了出售方便,必须把不同纯度的成品分开装箱,装箱员grant第1次顺序从流水线上取10个成品(如果一共不足10个,则全部取出),以后每一次把手中某种纯度的成品放进相应的箱子,然后再从流水线上顺序取一些成品,使手中保持10个成品(如果把剩下的全部取出不足10个,则全部取出),如果所有的成品都装进了箱子,那么grant的任务

P2530 [SHOI2001]化工厂装箱员

题目描述 118号工厂是世界唯一秘密提炼锎的化工厂,由于提炼锎的难度非常高,技术不是十分完善,所以工厂生产的锎成品可能会有3种不同的纯度,A:100%,B:1%,C:0.01%,为了出售方便,必须把不同纯度的成品分开装箱,装箱员grant第1次顺序从流水线上取10个成品(如果一共不足10个,则全部取出),以后每一次把手中某种纯度的成品放进相应的箱子,然后再从流水线上顺序取一些成品,使手中保持10个成品(如果把剩下的全部取出不足10个,则全部取出),如果所有的成品都装进了箱子,那么grant的任务

洛谷 p2530 化工场装箱员

化工场装箱员 https://www.luogu.org/problem/show?pid=2530 118号工厂是世界唯一秘密提炼锎的化工厂,由于提炼锎的难度非常高,技术不是十分完善,所以工厂生产的锎成品可能会有3种不同的纯 度,A:100%,B:1%,C:0.01%,为了出售方便,必须把不同纯度的成品分开装箱,装箱员grant第1次顺序从流水线上取10个成品(如果一 共不足10个,则全部取出),以后每一次把手中某种纯度的成品放进相应的箱子,然后再从流水线上顺序取一些成品,使手中保持10个成品

[题解]聪明的质检员

// 此博文为迁移而来,写于2015年7月14日,不代表本人现在的观点与看法.原始地址:http://blog.sina.com.cn/s/blog_6022c4720102w6ft.html 1.题目 2.TAG NOIP提高组:二分答案:前缀和. 3.分析 首先题面一定要看懂,看清(上次我就是没有看懂).说白了,就是使W取一个最合适的值,使每一个所给区间内满足条件的矿石的数量乘上价值之和,最后计算总和使与S最近. 我们根据分值分布来分析算法: 1.30分算法:O(n^3),首先O(n)进行W

经典的动态规划

有一个动态规划100例...看到机房里shenben的复习资料...加上垃圾的dp....整理一下. 一.资源分配问题 tyvj 1203 机器分配 题目大意:有m个设备,n个公司,v[i][j]表示第i个公司分j个设备的贡献值.怎样分配使贡献值的和最大? 状态:前i个公司分j个设备. f[i][j]表示前i个公司分j个设备,枚举第i个公司分k个设备. 状态转移方程:f[i][j]=max{f[i-1][j-k]+v[i][k]} 这个还挺简单的. 洛谷P2736 "破锣摇滚"乐队 R

08day2

引爆炸弹 贪心 [问题描述] 有 n 个炸弹,有些炸弹牵了一根单向引线(也就是说引线只有在这一端能被炸弹点燃),只要引爆了这个炸弹,用引线连接的下一个炸弹也会爆炸.每个炸弹还有个得分,当这个炸弹被引爆后就能得到相应得分.现在要你引爆 k 个炸弹,使得得分最大. [输入] 第一行两个整数 n.k. 接下来的 n 行,每行两个整数 a[i].b[i].a[i]表示这个炸弹用引线连接的下一个炸弹,如果a[i]为 0,则表示这个炸弹没有连接引线.b[i]表示这个炸弹的得分. [输出] 最大得分. [数据

二模08day2解题报告

T1.引爆炸弹(bomb) N个炸弹构成一棵树,引爆一颗叶节点,会一直引爆到根节点.每颗炸弹有一个价值,求引爆k个炸弹的最大价值. 既然是一棵树,那么自然想到dp.所以先树形dp了一遍(由于可能出现多个根节点所以要预处理).然后考虑到一个节点的最大价值的路径极有可能和另一路径重合导致重复,所以引入标记数组v[i],根据贪心思想,排排序取k个就好了. T2.取石子(stone) 一圈石子,各有分数,得分判断如下: 然后可以贪心,证明取一块或两块权值最大的石头是最优的. 现取lzw大神证明如下: 假

【LeetCode】前缀树 trie(共14题)

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica } [208]Implement Trie (Prefix Tree) (2018年11月27日) 实现基本的 trie 树,包括 insert, search, startWith 操作等 api. 题解:<程序员代码面试指南>chp5, 最后一题. 里面讲了怎么实现.这个就看代码吧.没啥好说的了. 1 class Trie { 2 public: 3 /** Ini