1. 程式人生 > 其它 >P2135 方塊消除

P2135 方塊消除

目錄
P2135 方塊消除

題目

https://www.luogu.com.cn/problem/UVA10559

https://www.luogu.com.cn/problem/P2135

題目描述

Jimmy最近迷上了一款叫做方塊消除的遊戲。遊戲規則如下:n個帶顏色方格排成一列,相同顏色的方塊連成一個區域(如果兩個相鄰方塊顏色相同,則這兩個方塊屬於同一區域)。為簡化題目,將連起來的同一顏色方塊的數目用一個數表示。

例如,9 122233331表示為

4 1 2 3 1

1 3 4 1

遊戲時,你可以任選一個區域消去。設這個區域包含的方塊數為x,則將得到x^2個分值。方塊消去之後,其餘的方塊就會豎直落到底部或其他方塊上。而且當有一列方塊被完全消去時,其右邊的所有方塊就會向左移一格。Jimmy希望你能找出得最高分的最佳方案,你能幫助他嗎?

輸入格式

第一行包含一個整數m(1<=m<=50),表示同顏色方塊區域的數目。第二行包含m個數,表示每個方塊的顏色(1到m之間的整數)。

輸出格式

僅一個整數,即最高可能得分。

輸入輸出樣例

輸入 #1

4

1 2 3 1

1 3 4 1

輸出 #1

29

思路

\(f_{i,j,k}\)表示消除\(l,r\)之間的方塊,其中顏色和\(i\)相同的方塊保留了\(k\)個時的最大得分.

對於初始化,顯然有:\(f_{i,i,0}=num_i^2,f_{i,i,num_i}=0\).其中\(num_i\)為第\(i\)個區域內方塊的數量.

轉移稍顯複雜,具體可以看程式碼,核心就是列舉保留還是消去.

程式碼

#include <iostream>
#include <cstdio>
#include <cstring>

#define int long long
using namespace std;
int read() {
	int re = 0;
	char c = getchar();
	bool negt = false;
	while(c < '0' || c > '9')
		negt |= (c == '-') , c = getchar();
	while(c >= '0' && c <= '9')
		re = (re << 1) + (re << 3) + c - '0' , c = getchar();
	return negt ? -re : re;
}

const int N = 210;
int col[N];//color
int num[N];
int f[55][55][1010];
int n;
int solve() {
	memset(col , 0 , sizeof(col));
	memset(num , 0 , sizeof(num));
	memset(f , 0 , sizeof(f));

	n = read();
	int sum = 0;
	for(int i = 1 ; i <= n ; i++)col[i] = read();
	for(int i = 1 ; i <= n ; i++)num[i] = read() , sum += num[i];

	memset(f , -0x3f , sizeof(f));

	for(int i = 1 ; i <= n ; i++)
		f[i][i][0] = num[i] * num[i] , f[i][i][num[i]] = 0;
	for(int i = n ; i > 0 ; i--)
		for(int j = i + 1 ; j <= n ; j++) {
			for(int k = i ; k < j ; k++) {
				f[i][j][0] = max(f[i][j][0] , f[i][k][0] + f[k + 1][j][0]);
				if(col[i] == col[k + 1])
					for(int l = 0 ; l <= sum ; l++) {//列舉[k+1,j]段留下l個顏色相同為col[i]的方塊
						f[i][j][l] = max(f[i][j][l] , f[i][k][0] + f[k + 1][j][l]);
						if(i + 1 <= k) {
							f[i][j][0] = max(
							                 f[i][j][0] ,
							                 f[i + 1][k][0] + f[k + 1][j][l] + (l + num[i]) * (l + num[i])
							             ) ;
							f[i][j][l + num[i]] = max(
							                          f[i][j][l + num[i]] ,
							                          f[i + 1][k][0] + f[k + 1][j][l]
							                      );

						}
					}
			} 
		}
	return f[1][n][0];
}

signed main() {
	printf("%lld" , solve());
	return 0;
}