BZOJ1806 [Ioi2007]Miners 矿工配餐 [动态规划]

矿工配餐

题目描述见链接 .


color{red}{正解部分}

F[i,a,b,c,d]F[i, a, b, c, d] 表示送完第 ii 次餐车, 第一个矿坑使用的最后两个元素为 a,ba,b, 第二个矿坑使用的最后两个元素为 c,dc,d 所能获得的最优值,

转移很显然:
F[i,si,a,c,d]=F[i1,a,b,c,d]+calc(a,b,si)F[i, s_i, a, c, d] = F[i-1, a, b, c, d] + calc(a, b, s_i)
F[i,a,b,si,c]=F[i1,a,b,c,d]+calc(c,d,si)F[i, a, b, s_i, c] = F[i-1, a, b, c, d] + calc(c, d, s_i)

时间复杂度 O(N44)O(N*4^4) .


color{red}{实现部分}

这道题目卡空间, 需要滚动数组 .

计算答案的函数需要注意不能这么写, 这么写会使得三个相同的情况返回 00 .

int calc(int a, int b, int c){
        if(!a && !b) return 1;
        else if(!a) return (b!=c)?2:1;
        return (a!=b) + (a!=c) + (b!=c);
}

#include<bits/stdc++.h>
#define reg register

const int maxn = 100005;

int N;
int t1;
int t2;
int Ans;
int Tong[4];
int F[2][4][4][4][4];

char S[maxn];

int Trans(char c){ return (c!='M')?(c!='B'?1:2):3; }

int calc(int a, int b, int c){
        int res = 0;
        Tong[1] = Tong[2] = Tong[3] = 0;
        if(a && (++ Tong[a]) == 1) res ++;
        if(b && (++ Tong[b]) == 1) res ++;
        if(c && (++ Tong[c]) == 1) res ++;
        return res;
}

int main(){
        scanf("%d", &N); scanf("%s", S+1);
        int cur = 0;
        memset(F, -1, sizeof F); F[0][0][0][0][0] = 0;
        for(reg int i = 1; i <= N; i ++){
                cur ^= 1; memset(F[cur], -1, sizeof F[cur]);
                for(reg int a = 0; a <= 3; a ++)
                        for(reg int b = 0; b <= 3; b ++)
                                for(reg int c = 0; c <= 3; c ++)
                                        for(reg int d = 0; d <= 3; d ++){
                                                if(F[cur^1][a][b][c][d] == -1) continue ;
                                                int now = Trans(S[i]);
                                                F[cur][now][a][c][d] = std::max(F[cur][now][a][c][d], F[cur^1][a][b][c][d] + calc(b, a, now));
                                                F[cur][a][b][now][c] = std::max(F[cur][a][b][now][c], F[cur^1][a][b][c][d] + calc(d, c, now));
                                        }
        } 
        for(reg int a = 0; a <= 3; a ++) 
                for(reg int b = 0; b <= 3; b ++) 
                        for(reg int c = 0; c <= 3; c ++) 
                                for(reg int d = 0; d <= 3; d ++) Ans = std::max(Ans, F[cur][a][b][c][d]);
        printf("%d
", Ans);
        return 0;
}
原文地址:https://www.cnblogs.com/zbr162/p/11822494.html