洛谷 P4401 [IOI2007]Miners 矿工配餐

题意简述

有两个矿洞,已知食物的种类(≤3)和顺序,将他们送往任一矿洞,
若一个矿洞3次食物相同,贡献1;若有2种不同食物,贡献2;若有3种不同食物,贡献3
求最大贡献

题解思路

food[i] 为当前食物
dp[i][i1][i2][i3][i4]表示当前是第i个食物,第一个矿洞前两次食物为i1, i2,第二个矿洞前两次食物为i3, i4
dp[i][i2][food[i]][i3][i4] = (dp[i - 1][i1][i2][i3][i4] + (i1, i2, food[i]) 的贡献, dp[i][i2][food[i]][i3][i4]);
dp[i][i1][i2][i4][food[i]] = (dp[i - 1][i1][i2][i3][i4] + (i3, i4, food[i]) 的贡献, dp[i][i1][i2][i4][food[i]]);

代码

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int n, ans;
int food[100010];
int dp[2][4][4][4][4];
char ch;
void maxx(int &x, int y) {x = max(x, y); }
int calc(int x, int y, int z) {return (y && y != z) + (x && x != y && x != z) + 1; }
int main()
{
    scanf("%d", &n);
    for (register int i = 1; i <= n; ++i)
    {
        cin >> ch;
        food[i] = ch == 'M' ? 1 : ch == 'F' ? 2 : 3;
    }
    memset(dp, -1, sizeof dp);
    dp[0][0][0][0][0] = 0;
    for (register int i = 1; i <= n ;++i)
        for (register int i1 = 0; i1 <= 3; ++i1)
            for (register int i2 = 0; i2 <= 3; ++i2)
                for (register int i3 = 0; i3 <= 3; ++i3)
                    for (register int i4 = 0; i4 <= 3; ++i4)
                        if (dp[(i - 1) & 1][i1][i2][i3][i4] != -1)
                        {
                            maxx(dp[i & 1][i2][food[i]][i3][i4], dp[(i - 1) & 1][i1][i2][i3][i4] + calc(i1, i2, food[i]));
                            maxx(dp[i & 1][i1][i2][i4][food[i]], dp[(i - 1) & 1][i1][i2][i3][i4] + calc(i3, i4, food[i]));
                        }
    for (register int i1 = 0; i1 <= 3; ++i1)
        for (register int i2 = 0; i2 <= 3; ++i2)
            for (register int i3 = 0; i3 <= 3; ++i3)
                for (register int i4 = 0; i4 <= 3; ++i4)
                    maxx(ans, dp[n & 1][i1][i2][i3][i4]);
    printf("%d
", ans); 
}

原文地址:https://www.cnblogs.com/xuyixuan/p/9460114.html