解题报告……?神奇的数列

发现最近一段时间发生了一些事情加上准备其他科的期末考试导致两个礼拜基本没有编程,算法能力直线下降……开始担心后天的考试了,大概率凉凉。
好的,正文。
描述
一个正整数数列,可以将它切割成若干个数据段,每个数据段由值相同的相邻元素构成。该数列的神奇之处在于,每次切除一个数据段后,
该数据段前后的元素自动连接在一起成为邻居。例如从数列“2 8 9 7 7 6 9 4”中切除数据段“7 7 ”后,余下的元素会构成数列“2 8 9 6 9 4”
请问若要将该数列切割成若干个数据段,则至少会切出来几个数据段?
样例: 按下列顺序切割数列“2 8 9 7 7 6 9 4”,只要切割成 6段
切割出“7 7”,余下 “2 8 9 6 9 4”
切割出 “6”,余下 “2 8 9 9 4”
切割出 “9 9”,余下 “2 8 4”
切割出 “2”,余下 “8 4”
切割出 “8”,余下 “4”

输入
第一行是一个整数,示共有多少组测试数据。每组测试数据的输入包括两行:第一行是整数N, N<=200,表示数列的长度,第二行是N个正整数。
输出
每个测试案例的输出占一行,是一个整数。格式是:
Case n: x
n是测试数据组编号,x是答案
样例输入
2
8
2 8 9 7 7 6 9 4
16
2 8 9 7 7 6 9 4 4 2 8 4 2 7 6 9
样例输出
Case 1: 6
Case 2: 11

发现自己动规实在是弱爆了。在做这个题的时候一开始本来想套讲义里的那个方盒游戏的套路,结果发现已经完全忘记那个题咋做的了。其实郭神的标答是少了一个参数的,这样就比较好思考了。然后我写的是递推式。状态转移方程是
if num[k] == num[j] score[i][j] = min { score[i][k]+score[k+1][j-1]}
else score[i][j] = min {score[i][j], score[i][k]+score[k+1][j]}
一开始想的是错的。在num[k]==num[j]的情况下我的状态转移方程是
score[i][j] = min { score[i][k-1]+score[k+1][j-1]+1, score[i][j] }
现在看来也是智障无比了……想的是中间的那个方块和后面的那个方块一起消掉……殊不知中间那个方块还能和前面的方块拼起来……醉了……
就这个问题比起积木的问题实际上是缺少了一个长度变量的,因为无论长度多少,最后的结果都是一样的,比如说ABAAB的情况,有很多种消法,两种消法的结果是一样的,但是那个方盒游戏就不行。也就是说,这个题目的目的就是要尽可能让数列的数字合并,合并的后果一定好于不合并的后果,但是方盒游戏是真的不一定。因此要加上右边大块的长度进行枚举让谁合并以及合并次数(不同合并的代价不一样,但是这个题目是一样的)
emmm感觉并没有把问题说清楚。大概的意思是,这个问题的score[i][j]是有最优子结构性的,整体最优一定是局部的最优解(后面还有同样花色的数字直接跟前面的代价最小的那个数字进行合并)。但是方盒游戏是不满足这个性质的。是否消去还和长度有关系。
好吧废话不说,AC代码如下。

#include 
#include 
using namespace std;
int score[202][202];
int N;
int num[202];
int main () {
	int T;
	//cin >> T;
	//freopen("C:\\Users\\csctest\\Desktop\\slin.txt", "r", stdin);
	//freopen("C:\\Users\\csctest\\Desktop\\sloutx.txt", "w", stdout); 
	scanf("%d", &T);
	int T0 = T;
	while (T--) {
		/*for (int i = 0; i < N; ++i) {
			for (int j = 0; j < N; ++j) {
				score[i][j] = 256;
			}
		}*/
		memset(score, 1, sizeof(score));
		memset(num, 0, sizeof(num));
		int N;
		scanf("%d", &N); //cin >> N;
		for (int i = 0; i < N; ++i) {
			scanf("%d", &num[i]); //cin >> num[i];
			score[i][i] = 1;
		}
		for (int i = 0; i < N; ++i) {
			for (int j = 0; j < i; ++j) {
				score[i][j] = 0;
			}
		}
		for (int i = 0; i < N-1; ++i) {
			if (num[i] == num[i+1]) score[i][i+1] = 1;
			else score[i][i+1] = 2;
		}
		for (int i = N - 2; i >= 0; --i) {
			for (int j = i + 1; j < N; ++j) {
				for (int k = i; k < j; ++k) {
					if (num[k] == num[j]) {
						score[i][j] = min(score[i][j], score[i][k] + score[k+1][j-1]);
					}
					score[i][j] = min(score[i][j], score[i][k] + score[k+1][j]);
				}
			}
		}
		/*
		for (int i = 0; i < N; ++i) {
			for (int j = 0; j < N; ++j) {
				if (score[i][j] < 10000 ) printf("%d ", score[i][j]);//cout << score[i][j] << " ";
				else printf("%d ", -1); //cout << -1 << " ";
			}
			printf("\n");//cout << endl;
		}*/
		printf("Case %d: %d\n", T0-T, score[0][N-1]);
		//cout << "Case " << T0-T << ": " <

我写的代码还有一个问题,在对拍的时候才发现……就是初始值的设定问题。score那个数组我全设置了个很大的数,导致递推的时候如果j

你可能感兴趣的:(C++)