【题解】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;
}

 

posted @ 2018-02-03 10:01  Twilight_Sx  阅读(144)  评论(0编辑  收藏  举报