题意:
一个历史考试,有n个历史事件, 它们之间的年份是不同的,要学生把这些事件按照正确的顺序排列出来。
有两种记分方式,采用的是第二种: 假设有历史事件1,2,3,4, 它们正确的时间顺序是1,2,3,4, 然后假设学生的答案是1,3,2,4, 那么按照相对顺序正确的数量,答对了三个(1,2,4或者1,3,4),也就是它与正确答案的最长公共子序列长度是3,便是答对的数量。
请你求出答对的数量。
解析:最长公共子序列的模板题,但是请注意先要将序列进行转换。
原序列是按时间顺序的事项排列,所以给你的排列要转化一下:例如:
10
3 1 2 4 9 5 10 6 8 7
意思是:1事项在第三个时间位置发生,2事项在第一个时间发生,以此类推……
转化为:2 3 1 4 6 8 10 9 5 7
一个历史考试,有n个历史事件, 它们之间的年份是不同的,要学生把这些事件按照正确的顺序排列出来。
有两种记分方式,采用的是第二种: 假设有历史事件1,2,3,4, 它们正确的时间顺序是1,2,3,4, 然后假设学生的答案是1,3,2,4, 那么按照相对顺序正确的数量,答对了三个(1,2,4或者1,3,4),也就是它与正确答案的最长公共子序列长度是3,便是答对的数量。
请你求出答对的数量。
解析:最长公共子序列的模板题,但是请注意先要将序列进行转换。
原序列是按时间顺序的事项排列,所以给你的排列要转化一下:例如:
10
3 1 2 4 9 5 10 6 8 7
意思是:1事项在第三个时间位置发生,2事项在第一个时间发生,以此类推……
转化为:2 3 1 4 6 8 10 9 5 7
转换完后,按照最长公共子序列的模板求解。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 25;
int dp[N][N];
int goal[N];
int num[N];
int main() {
int n,pos;
scanf("%d",&n);
for(int i = 1; i <= n; i++) {
scanf("%d",&pos);
goal[pos] = i;
}
while(scanf("%d",&pos) != EOF) {
num[pos] = 1;
for(int i = 2; i <= n; i++) {
scanf("%d",&pos);
num[pos] = i;
}
memset(dp,0,sizeof(dp));
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= n; j++) {
if(num[j] == goal[i]) {
dp[i][j] = dp[i-1][j-1]+1;
}else {
dp[i][j] = max(dp[i-1][j],dp[i][j-1]);
}
}
}
printf("%d\n",dp[n][n]);
}
return 0;
}