#include <stdio.h>
#include <memory.h>
#include <algorithm>
using namespace std;
#define MAX 32767
#define MIN -32767
int b[105][105] = {0}; //用于构造最长公共子序列
int c[105][105] = {0}; //记录最长公共子序列长度
int normal[105] = {0}; //记录身高序列
int n; //记录身高序列的长度
int increase[105] = {0}; //记录递增序列
int decrease[105] = {0}; //记录递减序列
int temp1[105] = {0}; //记录最长递增子序列
int count1 = 0; //记录最长递增子序列的长度
int temp2[105] = {0}; //记录最长递减子序列
int count2 = 0; //记录最长递减子序列的长度
int m1 = 0, m2 = 0; //分别记录递增和递减序列的长度
//排序函数的一个参数,逆序用的
int cmp(int aa, int bb) {
return aa>bb;
}
//求最长公共子序列
void LCSLength(int x[], int y[], int m, int n) {
// for (int i = 0; i <= m; i++) {
// c[i][0] = 0;
// }
// for (int i = 0; i <= n; i++) {
// c[0][i] = 0;
// }
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
if (x[i - 1] == y[j - 1]) {
c[i][j] = c[i - 1][j - 1] + 1;
b[i][j] = 0;
} else if (c[i - 1][j] >= c[i][j - 1]) {
c[i][j] = c[i - 1][j];
b[i][j] = 1;
} else {
c[i][j] = c[i][j - 1];
b[i][j] = -1;
}
}
}
}
//构造最长公共子序列,递增
void printLCS1(int x[], int m, int n, int temp[]) {
int i = m;
int j = n;
if (i == 0 || j == 0) {
return;
}
if (b[i][j] == 0) {
printLCS1(x, i - 1, j - 1, temp);
temp[count1++] = x[i - 1];
// printf("%d ", x[i - 1]);
} else if (b[i][j] == 1) {
printLCS1(x, i - 1, j, temp);
} else {
printLCS1(x, i, j - 1, temp);
}
}
//构造最长公共子序列,递减
void printLCS2(int x[], int m, int n, int temp[]) {
int i = m;
int j = n;
if (i == 0 || j == 0) {
return;
}
if (b[i][j] == 0) {
printLCS2(x, i - 1, j - 1, temp);
temp[count2++] = x[i - 1];
// printf("%d ", x[i - 1]);
} else if (b[i][j] == 1) {
printLCS2(x, i - 1, j, temp);
} else {
printLCS2(x, i, j - 1, temp);
}
}
/*
* N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的 K位同学排成合唱队形。
* 合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1,2…,K,他们的身高分别为T1,T2,…,TK,
* 则他们的身高满足T1 < T2 < ...< Ti > Ti+1 > … > TK (1 <= i <= K)。
* 你的任务是,已知所有N位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。
* Input
* 输入包含若干个测试用例。
* 对于每个测试用例,输入第一行是一个整数N(2<=N<=100),表示同学的总数。
* 第二行有N个整数,用空格分隔,第i个整数 Ti(130<=Ti<=230)是第i位同学的身高(厘米)。
* 当输入同学总数N为0时表示输入结束。
* Output
* 对于每个测试案例,输出包括一行,这一行只包含一个整数,就是最少需要几位同学出列。
* Sample Input
* 8
* 186 186 150 200 160 130 197 220
* 3
* 150 130 140
* 0
* Sample Output
* 4
* 1
* Hint
* 合唱队形满足T1 < T2 < ...< Ti > Ti+1 > … > TK (1 <= i <= K),其中里面最具有指标性意义的人是Ti,
* 由于(1 <= i <= K),意味着每个人都可能是作为中间的指标性人物,因此可枚举所有情况.
* 对于每种情况,指标性人物往左应求一个最长的队列,往右也应求一最长的队列(当然此队列要包含指标人物本身).
* 如下例:
* 8个人
* 186 186 150 200 160 130 197 220
* 以第i个人作为中心往左的最长序列:1 1 1 2 2 1 3 4
* 以第i个人作为中心往右的最长序列:3 3 2 3 2 1 1 1
*
* 思路:
* 求身高序列的最长递增(注意不是非递减)子序列和最长递减(注意不是递增)子序列
* 然后两个序列合并即可以求出最长的合唱队形,然后就可以求出去除的人数了
* 而最长递增和最长递减子序列时,可以先排序,再去除重复的,转为求最长公共子序列
*/
int main() {
int i, j, result;
while (scanf("%d", &n)) {
m1 = n;
m2 = n;
if (n == 0) {
break;
}
for (i = 0; i < n; i++) {
scanf("%d", &normal[i]);
decrease[i] = normal[i];
increase[i] = normal[i];
}
//排序
sort(increase, increase + n);
sort(decrease, decrease + n, cmp);
//去掉重复的数字,把重复的数字置最大值,排序后取前面的数
for (i = 0, j = 1; i < n;) {
if (increase[i] == increase[j]) {
increase[i] = MAX;
i = j;
j++;
m1--;
} else {
i++;
j++;
}
}
sort(increase, increase + n);
//去掉重复的数字,把重复的数字置最小值,排序后取前面的数
for (i = 0, j = 1; i < n;) {
if (decrease[i] == decrease[j]) {
decrease[i] = MIN;
i = j;
j++;
m2--;
} else {
i++;
j++;
}
}
sort(decrease, decrease + n, cmp);
//求最长递增子序列
LCSLength(normal, increase, n, m1);
count1 = 0;
printLCS1(normal, n, m1, temp1);
// for (i = 0; i < count1; i++) {
// printf("%d ", temp1[i]);
// }
// printf("\n");
memset(c, 0, sizeof (c));
memset(b, 0, sizeof (b));
//求最长递减子序列
LCSLength(normal, decrease, n, m2);
count2 = 0;
printLCS2(normal, n, m2, temp2);
// for (i = 0; i < count2; i++) {
// printf("%d ", temp2[i]);
// }
// printf("\n");
//合并两个最长递增和递减子序列,排成合唱队形
for (i = count1 - 1, j = 0; i >= 0 && j < count2;) {
if (temp1[i] > temp2[j]) {
i--;
} else if (temp1[i] < temp2[j]) {
j++;
} else {
break;
}
}
if (count1 == 0 || count2 == 0) {
result = 0;
} else if (i < 0 || j >= count2) {
result = count1 > count2 ? count1 : count2;
result = n - result;
} else {
result = n - (i + count2 - j);
int tem = count1 > count2 ? count1 : count2;
tem = n - tem;
result = tem < result ? tem : result;
}
//输出去掉最少的人数
printf("%d\n", result);
memset(c, 0, sizeof (c));
memset(b, 0, sizeof (b));
memset(temp1, 0, sizeof (temp1));
memset(temp2, 0, sizeof (temp2));
}
return 1;
}
分享到:
相关推荐
根据给定的信息,本文将详细解释“合唱队形”这一概念以及如何通过编程解决与之相关的实际问题。本文首先会介绍合唱队形的基本定义及其在实际中的应用背景,随后将详细解析给定代码的主要功能及其实现逻辑。 ### ...
N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学排成合唱队形。 合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1,2…,K,他们的身高分别为T1,T2,…,TK, 则他们的身高...
此题是NOIP(全国青少年信息学奥林匹克联赛)中的一道经典算法题,题目名为“合唱队形”(ChorusBy Len),主要考察的是动态规划和分割序列的优化策略。以下是对该题目的详细分析: 1. **问题理解**: - 给定一个...
2. 合唱队形定义:合唱队形是指在一行同学中,找到一段子序列,使得这段子序列满足两边的同学身高较低,中间的同学身高递增然后递减。即对于任一中间位置的i(1 ),都存在T1 < T2 < ... < Ti > Ti+1 > ... > TK。 ...
N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学排成合唱队形。 合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1,2…,K,他们的身高分别为T1,T2,…,TK, 则他们的身高...
DP系列
3. **歌曲选择与排练方法**:选择适合合唱的歌曲,如《唱歌祖国》,并结合传统的四声部合唱队形进行创新。利用梯形或倒梯形队形,以女高、女低、男高、男低四个基本声部为基础,灵活调整。排练时,要挑选声部小队长...
本教(学)案旨在详细阐述歌唱的姿势以及合唱队形编排的两个重要方面,以期提升学生的合唱水平和整体音乐素养。 首先,歌唱姿势是合唱训练中的基础环节,它直接关系到演唱者发声的质量和身体的健康。在教学中,教师...
《动态规划算法实验》实验报告主要探讨了两个经典动态规划问题——0-1背包问题和合唱队形安排问题。这两个问题都是在优化决策过程中寻找最优解的经典实例。 **一、0-1背包问题** 0-1背包问题是一个经典的约束优化...
2. **合唱队形问题**:要求找到最少需要出列的同学数量,使得剩下的同学能形成合唱队形(即身高从左到右先增后减)。同样可以采用动态规划。我们可以遍历所有同学,对于每个学生,检查其左侧是否存在严格升序的子...
《合唱排练软件 合唱排练系统 v1.06》是一款专为合唱团设计的高效排练工具,旨在提升合唱团的练习效果和整体和谐性。该软件集成了多种功能,包括分声部教学、节拍器、伴奏控制等,能够满足不同层次合唱团队的需求。 ...
- 不同声部的队形安排:如两声部、三声部和混声四部的合唱队形设计。 8. **合唱的基本训练**: - 发声训练:采用胸腹式联合呼吸法,深呼吸并将气息扩展至腰部,保持横膈膜的张力,以实现稳定而有力的发声。 这些...
题目要求从一组学生中选出满足特定条件的子集,即这些子集内的学生按身高排列形成合唱队形,即部分子集内的学生身高是单调递增的,部分是单调递减的。解决此类问题,可以使用动态规划方法,通过比较每个学生的身高和...
砝码称重问题、最小乘车费用问题、合唱队形问题和观光游览问题等,均需要参赛者对算法有深入的理解,并具备良好的问题解决能力。通过这些题目的训练,不仅可以提升参赛者的逻辑思维能力、分析能力和编程技巧,还能在...
合唱队形问题则需要同时从两端寻找最长的上升子序列,最终找到使K位同学满足合唱队形条件的最小人数。 滑雪问题实质上也是最长上升子序列的变种,通过调整高度数组,我们可以从高到低遍历,找到最长的“下坡”路径...
1008 合唱队形 1017 最大0,1子矩阵 这题要想不超时,必须DP 1020 最大正方形 这题和1017很相似,不过有更快的解决方法 1021 背包问题 1022 Longest Common Sequence 也可用二叉搜索树(nlog时间)解决,见llj的书 ...
要形成合唱队形,需要找到最小的K使得剩下的K个人按身高排列后满足条件。可以先对所有身高进行排序,然后从两边向中间扫描,统计满足条件的子序列。 T4 题目是一个经典的最优化问题,类似于区间覆盖。通过线段树或...
3. 动态规划算法:实验内容包括0-1背包问题和合唱队形安排的编程解决。学生需掌握动态规划的基本策略,学习如何构建最优解决方案。 4. 回溯算法:实验涵盖了8皇后问题和批处理作业调度的回溯法求解。学生需理解回溯...
3. **小华、小芳和小红的合唱队形**: 类似于上一题的排列问题,但这里考察的是三个人的排列,而不是三个位置。因为每个人都可以站在队伍的开头、中间或结尾,所以总共有3!(3的阶乘)种排列方式,即3种不同的队形...
学生们自编自演的节目精彩纷呈,尤其是六(1)班的合唱队形设计,展现了团队合作的力量。一年级的小朋友冯莹的精彩表演更是赢得了现场的热烈掌声,体现出了学校艺术教育的成果和孩子们对节日的热爱。 此外,活动...