给出一个只包含 0 和 1 的 01 串 s ,下标从 1 开始,设第 i 位的价值为 vali ,则价值定义如下:
i=1时:val1 = 1
i>1时:
2.1 若 si ≠ si-1 , vali = 1
2.2 若 si = si-1 , vali = vali-1 + 1
字符串的价值等于 val1 + val2 + val3 + … + valn
你可以删除 s 的任意个字符,问这个串的最大价值是多少。
思路:
1、整合字符串,将连续的1和连续的0看成是一个元素,可以减少需要处理的数据量
2、删除元素时候,连续的0和连续的1要么都删除,要么都保留
3、如果整合后的字符串元素数量小于40,进行递归计算,否则按照谁多留下谁,同时留下两端的异类。(如果1的数量大于0的数量,则删除所有的0,只留下两端的0,反之亦然)
代码如下:
#include <stdio.h>
struct data_compress {
int subValue; //这部分连续字串的value
int cont_num; //连续0或者连续1的长度
char source_value; //标识当前字串是1还是0
};
int cacu_count_value(int cont_num) {
return cont_num * (cont_num + 1) / 2;
}
int max_value = 0;
/* 递归计算,选取最大值 */
void cacu_max_value(struct data_compress* data, int depth, int depthMax,
int cacuValue, int cont_num) {
//printf("depth = %d cacuValue = %d cont_num = %d \n",depth,cacuValue,cont_num);
int result;
if (depth == depthMax - 1) {
result = cacuValue + cont_num * (cont_num + 1) / 2;
if (max_value < result) max_value = result;
}
if (depth + 1 < depthMax) {
cacu_max_value(&data[1], depth + 1, depthMax, cacu_count_value(cont_num),
data[1].cont_num);
}
if (depth + 2 < depthMax) {
cacu_max_value(&data[2], depth + 2, depthMax, cacuValue,
cont_num + data[2].cont_num);
}
return;
}
int main() {
char array[5005];
struct data_compress com_data[5005];
int count;
while (scanf("%d", &count) != EOF) { // 注意 while 处理多个 case
scanf("%s", array);
int cont_num = 0;
int compress_num = 0;
for (int i = 1; i < count; i++) {
if (array[i] != array[i - 1]) {
cont_num++;
//printf("%d %d\n",com_data[compress_num].subValue, cont_num);
com_data[compress_num].source_value = array[i - 1];
com_data[compress_num].cont_num = cont_num;
com_data[compress_num].subValue = cont_num * (cont_num + 1) / 2;
compress_num++;
cont_num = 0;
} else {
cont_num++;
}
}
cont_num++;
com_data[compress_num].source_value = array[count - 1];
com_data[compress_num].cont_num = cont_num;
com_data[compress_num].subValue = cont_num * (cont_num + 1) / 2;
int num_1 = 0, num_0 = 0, max_con = 0;
if (compress_num > 40) { //元素数量大于40,选取多的元素进行组合计算
max_value = 0;
for (int i = 0 ; i <= compress_num; i++) {
if (com_data[i].source_value == '0') num_0 = num_0 + com_data[i].cont_num;
if (com_data[i].source_value == '1') num_1 = num_1 + com_data[i].cont_num;
}
if (num_0 > num_1) {
max_con = num_0;
if (com_data[0].source_value == '1') max_value += cacu_count_value(
com_data[0].cont_num);
if (com_data[compress_num].source_value == '1') max_value += cacu_count_value(
com_data[compress_num].cont_num);
max_value += cacu_count_value(max_con);
} else { // 元素数量小于40,进行递归计算
max_con = num_1;
if (com_data[0].source_value == '0') max_value += cacu_count_value(
com_data[0].cont_num);
if (com_data[compress_num].source_value == '0') max_value += cacu_count_value(
com_data[compress_num].cont_num);
max_value += cacu_count_value(max_con);
}
} else {
cacu_max_value(com_data, 0, compress_num + 1, 0, com_data[0].cont_num);
}
printf("%d \n", max_value);
for (int i = 0 ; i <= compress_num; i++) { //这个循环时调试打印
//printf("%d, %d\n",max_value, com_data[i].cont_num);
}
}
return 0;
}
这个代码可以通过18个案例,最后一个案例过不了。最后验算了一个,发现是腾讯给的答案是错的。
用例如下:
长度1000,具体值如下:
"1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000011111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001111111111111110000000"
序列 | 字符值 | 长度 |
---|---|---|
1 | 1 | 714 |
2 | 0 | 38 |
3 | 1 | 45 |
4 | 0 | 181 |
5 | 1 | 15 |
6 | 0 | 7 |
根据连续字符提取为1个元素的方法,一共提取了6个元素。根据网上给的答案,是将第二个和第四个元素删除最后变成了两个元素。
第一个元素长度:714+45+15 = 774。按照题目给的方法计算结果是299925
第二个元素长度:7.按照题目给的方法计算结果是28。
两个元素相加 299925 + 28 =299953。
=============================================================
实际程序删除第二个和第五个得到最大值,同样是变成两个元素。
第一个元素长度:714 + 45 = 759。按照题目给的方法计算结果是288420
第二个元素长度:181 + 7 = 188。按照题目给的方法计算结果是17766
两个值相加:288420+ 17766= 306186