A. 拍照
Description
最近,文明班级需要拍集体照,N位同学站成一排,为了美观,老师要请其中的(N-K)位同学出列,使得剩下的K位同学排成中间高两边低的队形。这种队形是:设K位同学从左到右依次编号为1,2…,K,他们的身高分别为T1,T2,…,TK, 则他们的身高满足T1<…Ti+1>…>TK(1<=i<=K)。你的任务是,已知所有N位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成这种队形。
Input
输入的第一行是一个整数N(2<=N<=100),表示同学的总数。第二行有n个整数,用空格分隔,第i个整数Ti (130<= Ti <=230)是第i位同学的身高(厘米)。
Output
输出包括一行,这一行只包含一个整数,就是最少需要几位同学出列。
Sample Input
8
186 186 150 200 160 130 197 220
Sample Output
4
Answer
#include<bits/stdc++.h>
using namespace std;
int a[10001],dp[10001],indexs[10001];
int main() {
int i,j,k,n,mx,index,indexCnt;
while(1==scanf("%d",&n)) {
for(i=1; i<=n; i++) {
scanf("%d",&a[i]);
}
for(i=1; i<=n; i++) {
dp[i]=1;
}
mx=1;
index=n;
indexCnt=0;
indexs[++indexCnt]=index;
for(i=n-1; i>=1; i--) {
for(j=i+1; j<=n; j++) {
if(a[i]>a[j]&&dp[i]<dp[j]+1) {
dp[i]=dp[j]+1;
}
}
if(mx<dp[i]) {
mx=dp[i];
index=i;
indexs[++indexCnt]=index;
}
}
index=4;
for(k=1; k<=indexCnt; k++) {
index=indexs[k];
for(i=index-1; i>=1; i--) {
for(j=i+1; j<=n; j++) {
if(a[i]<a[j]) {
dp[i]=max(dp[i],dp[j]+1);
}
}
mx=max(mx,dp[i]);
}
}
printf("%d\n",n-mx);
}
return 0;
}
B. 数字三角形问题A
Description
设有一个三角形的数塔,顶点结点称为根结点,每个结点有一个整数数值。从顶点出发,可以向左走,也可以向右走。如图所示:
当三角形的数塔给定之后,找出一条从第一层到达底层的路径,使路径的值(路径上的圈内的数字之和)最小。
Input
本问题有多组测试数据,第一行就是测试数据的组数,对于每一组测试数据,共有两部分,其中第一部分是一行,即层数L(1<=L<=100),第二部分有L行,每行有L个数字,0<=数字<=1000,数字之间有空格。
Output
对于每一组测试数据,输出只有一行,就是最小的路径值。
Sample Input
1
5
13
11 8
12 7 26
6 14 15 8
12 7 13 24 11
Sample Output
49
Answer
#include<bits/stdc++.h>
using namespace std;
int n,a[100][100],f[100][100],ans,repeat;
int main() {
scanf("%d",&repeat);
while(repeat--) {
scanf("%d",&n);
for (int i = 1; i <= n; i++)
for (int j = 1; j <=i; j++)
scanf("%d",&a[i][j]);
//第一排的第一个数字用于作为动态规划的基础
f[1][1] = a[1][1];
for (int i = 2; i <= n; i++)
for (int j = 1; j <=i; j++) {
//如果是这一行的第一个数,则与上一行第一个的最优解相加
if(j==1){
f[i][j]=f[i-1][j]+a[i][j];
}
//如果是这一行的最后一个数,则与上一行最后一个的最优解相加
else if(j==i){
f[i][j]=f[i-1][j-1]+a[i][j];
}
//如果是其他的数,则取两个中最小的那个作为最优解
else{
f[i][j] = min(f[i-1][j-1]+a[i][j],f[i-1][j]+a[i][j]);
}
}
ans = f[n][1];
//在最后一层中找答案(最小值)
for (int i = 2; i <= n; i++)
ans = min(ans,f[n][i]);
printf("%d\n",ans);
}
}
C. 最长不下降子序列
Description
一个数的序列bi,当b1 <= b2 <= … < =bS的时候,我们称这个序列是不下降的。对于给定的一个序列(a1, a2, …, aN),我们可以得到一些不下降的子序列(ai1, ai2, …, aiK),这里1<= i1 < i2 < … < iK <= N。比如,对于序列(1, 7, 3, 5, 9, 4, 8),有它的一些不下降子序列,如(1, 7), (3, 4, 8)等等。这些子序列中最长的长度是4,比如子序列(1, 3, 5, 8)。
Input
多组cas , 每组cas 两行:
第一行 输入一个数 n (n < 10000), 表示有n个数
第二行 n个数, 分别代表每个数;
Output
每个cas 一行 输出该序列最长不下降子序列的长度 ;
Sample Input
7
1 7 3 5 9 4 8
Sample Output
4
Answer
#include<bits/stdc++.h>
using namespace std;
int a[10001],dp[10001];
int main() {
int i,j,n,mx;
while(1==scanf("%d",&n)) {
for(i=1; i<=n; i++) {
scanf("%d",&a[i]);
}
for(i=1; i<=n; i++) {
dp[i]=1;
}
mx=1;
for(i=n-1; i>=1; i--) {
for(j=i+1; j<=n; j++) {
if(a[i]<=a[j]) {
dp[i]=max(dp[i],dp[j]+1);
}
}
mx=max(mx,dp[i]);
}
printf("%d\n",mx);
}
return 0;
}
D. 最长不下降子序列问题(输出序列)
Description
Input
本问题有多组测试数据,对于每组测试数据,输入有两行;第一行n表示序列的元素个数,1<=n<=10000;第二行是用空格隔开的n个整数,表示由n个整数组成的序列。
Output
对于每一组测试数据,输出有两行,第一行为最长的子序列的长度;第二行是用空格隔开的子序列,行尾没有空格。
Sample Input
7
1 7 3 5 9 4 8
14
13 7 9 16 38 24 37 18 44 19 21 22 63 15
Sample Output
4
1 3 5 9
8
7 9 16 18 19 21 22 63
Answer
#include<bits/stdc++.h>
using namespace std;
int a[10001],dp[10001],b[10001];
int h;
int main() {
int i,j,n,mx;
while(1==scanf("%d",&n)) {
for(i=1; i<=n; i++) {
scanf("%d",&a[i]);
}
for(i=1; i<=n; i++) {
dp[i]=1;
b[i]=i;
}
mx=1;
h=1;
for(i=n-1; i>=1; i--) {
for(j=i+1; j<=n; j++) {
if(a[i]<=a[j]&&dp[i]<dp[j]+1) {
dp[i]=dp[j]+1;
// 数组b 中存了子序列各元素的在a数组的下标
// b[i]=j -> b[j]=k ->b[k]
b[i]=j;
}
}
if(mx<=dp[i]) {
mx=dp[i];
// h是子序列第一个数的下标
h=i;
}
}
printf("%d\n",mx);
printf("%d",a[h]);
for(i=1; i<mx; i++) {
h=b[h];
printf(" %d",a[h]);
}
printf("\n");
}
return 0;
}