首页 > 试题广场 >

小明打砖块

[编程题]小明打砖块
  • 热度指数:589 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
小明在玩一个消除游戏。这个消除游戏有点特别。游戏中,你会得到 n 个一维排列的有各自颜色的砖块。
消除的时候,你有三种消除方案。你可以单消一个砖块,这样你可以得到 a 的得分;如果两个颜色一样的砖块在一起,你可以将这两个砖块一起消除获得 b 的得分;如果三个颜色一样的砖块在一期,你可以将这三个砖块一起消除获得 c 的得分。
消除后,被消除的砖块自动消失,被消除砖块的左右两端的砖块将在消除之后挨在一起。
小明想知道在最优策略下他能得到多少得分。

输入描述:
第一行4个整数n,a,b,c,表示砖块数量,和一消/二消/三消的得分。
接下来一行n个整数,第i 个整数 s_i 表示第 i 个砖块的颜色。

1 \leq s_i \leq n \leq 300, 0 \leq a,b,c \leq 10000


输出描述:
输出最高得分
示例1

输入

8 1 3 7
3 1 3 1 3 2 2 3

输出

14
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int n, a, b, c;
    cin >> n >> a >> b >> c;
    
    vector<int> s(n);
    for (int i = 0; i < n; ++i) {
        cin >> s[i];
    }
    
    // 预处理每个位置j前面相同颜色的位置(升序存储)
    vector<vector<int>> prev(n);
    for (int j = 0; j < n; ++j) {
        for (int i = 0; i < j; ++i) {
            if (s[i] == s[j]) {
                prev[j].push_back(i);
            }
        }
    }
    
    // 初始化DP数组
    vector<vector<int>> dp(n, vector<int>(n, 0));
    for (int i = 0; i < n; ++i) {
        dp[i][i] = a; // 单个砖块只能单消
    }
    
    // 区间DP,按区间长度从小到大计算
    for (int len = 2; len <= n; ++len) {
        for (int i = 0; i + len <= n; ++i) {
            int j = i + len - 1;
            dp[i][j] = 0;
            
            // 情况1:分割成两个子区间
            for (int k = i; k < j; ++k) {
                dp[i][j] = max(dp[i][j], dp[i][k] + dp[k+1][j]);
            }
            
            // 情况2:单消最后一个砖块
            dp[i][j] = max(dp[i][j], dp[i][j-1] + a);
            
            // 情况3:寻找同色砖块,处理双消或三消
            for (int k : prev[j]) {
                if (k < i) continue; // k必须在[i, j-1]范围内
                
                // 双消:k和j
                int current = 0;
                if (k > i) current += dp[i][k-1];
                if (k+1 <= j-1) current += dp[k+1][j-1];
                current += b;
                dp[i][j] = max(dp[i][j], current);
                
                // 三消:寻找k前面的同色m,形成m、k、j三消
                for (int m : prev[k]) {
                    if (m < i) continue;
                    
                    int temp = 0;
                    if (m > i) temp += dp[i][m-1];
                    if (m+1 <= k-1) temp += dp[m+1][k-1];
                    if (k+1 <= j-1) temp += dp[k+1][j-1];
                    temp += c;
                    dp[i][j] = max(dp[i][j], temp);
                }
            }
        }
    }
    
    cout << dp[0][n-1] << endl;
    return 0;
}


发表于 2025-08-13 18:00:53 回复(0)
import java.util.Scanner;

// DP[i][j]:单消、双消、三消
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int a = in.nextInt(), b = in.nextInt(), c = in.nextInt();
        int[] s = new int[n];
        for (int i = 0; i < n; i++) {
            s[i] = in.nextInt();
        }

        int[][] dp = new int[n][n];
        for (int len = 1; len <= n; len++) {
            for (int i = 0; i + len - 1 < n; i++) {
                int j = i + len - 1, res = 0;

                // 单消:枚举s[k]  
                for (int k = i; k <= j; k++) {
                    int l = (i <= k - 1) ? dp[i][k - 1] : 0; // s[i]还在
                    int r = (k + 1 <= j) ? dp[k + 1][j] : 0;
                    res = Math.max(res, a + l + r);
                }

                // 双消:枚举s[k]和s[i]匹配
                for (int k = i + 1; k <= j; k++) {
                    if (s[k] != s[i]) continue;
                    int l = (i + 1 <= k - 1) ? dp[i + 1][k - 1] : 0; // s[i]没了
                    int r = (k + 1 <= j)     ? dp[k + 1][j]     : 0;
                    res = Math.max(res, b + l + r);
                }

                // 三消:枚举s[k]、s[t]和s[i]匹配
                for (int k = i + 1; k < j; k++) {
                    if (s[k] != s[i]) continue;
                    for (int t = k + 1; t <= j; t++) {
                        if (s[t] != s[i]) continue;
                        int l = (i + 1 <= k - 1) ? dp[i + 1][k - 1] : 0;
                        int m = (k + 1 <= t - 1) ? dp[k + 1][t - 1] : 0;
                        int r = (t + 1 <= j)     ? dp[t + 1][j]     : 0;
                        res = Math.max(res, c + l + m + r);
                    }
                }
                dp[i][j] = res;
            }
        }
        System.out.println(dp[0][n - 1]);
    }
}

发表于 2025-10-27 22:37:39 回复(0)
#include <bits/stdc++.h>
using namespace std;

int n;
int a, b, c;
vector<int> color;
vector<int> bestScore;
unordered_map<long long,int> memo;

inline long long encode(int l,int r,int k){
    return ((long long)l<<40) | ((long long)r<<20) | k;
}

int dfs(int l,int r,int k){
    if(l>r) return 0;
    long long key=encode(l,r,k);
    if(memo.count(key)) return memo[key];

    int ans = dfs(l,r-1,0) + bestScore[k+1];

    for(int i=l;i<r;i++){
        if(color[i]==color[r]){
            ans = max(ans, dfs(l,i,k+1) + dfs(i+1,r-1,0));
        }
    }

    return memo[key]=ans;
}

int main(){
    cin>>n>>a>>b>>c;
    color.resize(n);
    for(int i=0;i<n;i++) cin>>color[i];

    bestScore.assign(n+5,-1e9);
    bestScore[0]=0;
    for(int i=1;i<=n;i++){
        if(i>=1) bestScore[i] = max(bestScore[i], bestScore[i-1]+a);
        if(i>=2) bestScore[i] = max(bestScore[i], bestScore[i-2]+b);
        if(i>=3) bestScore[i] = max(bestScore[i], bestScore[i-3]+c);
    }

    cout<<dfs(0,n-1,0);
    return 0;
}
发表于 2025-08-20 20:33:36 回复(0)