UVA111 History Grading【LCS+DP+记忆化递归】

Many problems in Computer Science involve maximizing some measure according to constraints.
    Consider a history exam in which students are asked to put several historical events into chronological order. Students who order all the events correctly will receive full credit, but how should partial credit be awarded to students who incorrectly rank one or more of the historical events?
    Some possibilities for partial credit include:

  1. 1 point for each event whose rank matches its correct rank
  2. 1 point for each event in the longest (not necessarily contiguous) sequence of events which are in the correct order relative to each other.

For example, if four events are correctly ordered 1 2 3 4 then the order 1 3 2 4 would receive a score of 2 using the first method (events 1 and 4 are correctly ranked) and a score of 3 using the second method (event sequences 1 2 4 and 1 3 4 are both in the correct order relative to each other).
    In this problem you are asked to write a program to score such questions using the second method.
    Given the correct chronological order of n events 1, 2, . . . , n as c1, c2, . . . cn where 1 ≤ ci ≤ n denotes the ranking of event i in the correct chronological order and a sequence of student responses r1, r2, . . . , rn where 1 ≤ ri ≤ n denotes the chronological rank given by the student to event i; determine the length of the longest (not necessarily contiguous) sequence of events in the student responses that are in the correct chronological order relative to each other.
Input
The input file contains one or more test cases, each of them as described below.
    The first line of the input will consist of one integer n indicating the number of events with 2 ≤ n ≤ 20. The second line will contain n integers, indicating the correct chronological order of n events. The remaining lines will each consist of n integers with each line representing a student’s chronological ordering of the n events. All lines will contain n numbers in the range [1 . . . n], with each number appearing exactly once per line, and with each number separated from other numbers on the same line by one or more spaces.
Output
For each test case, the output must follow the description below
    For each student ranking of events your program should print the score for that ranking. There should be one line of output for each student ranking.
Warning: Read carefully the description and consider the difference between ’ordering’ and ’ranking’.
Sample Input
4
4 2 3 1
1 3 2 4
3 2 1 4
2 3 4 1
10
3 1 2 4 9 5 10 6 8 7
1 2 3 4 5 6 7 8 9 10
4 7 2 3 10 6 9 1 5 8
3 1 2 4 9 5 10 6 8 7
2 10 1 3 8 4 9 5 7 6
Sample Output
1
2
3
6
5
10
9

问题链接UVA111 History Grading
问题简述:给定一个n 代表序列中元素的个数, 其后是一组答案, 接下来是若干个同学的答案(直到文件结束为止), 求出两个序列的最长公共子序列。需要注意给出的答案均是以该事件处于第几个发生的, 例如 :2 3 4 1。
问题分析
    给出的答案是事件的发生序号,需要做一下转换。
    最长公共子序列的模板题,根据状态转换方程计算即可。状态转换方程如下:
d[i][j] =

  1. 0 若 i = 0 || j = 0
  2. d[i - 1] [j - 1] + 1 若 a[i] = b[i]
  3. max(d[i - 1][j] , d[i] [j - 1]) 其他情况

    对于动态规划问题,得到状态转换方程后,也可以使用记忆化递归来实现。采用记忆化递归的缺点是计算时间略长,因为需要付出函数调用返回以及参数传递的代价;其优点是程序逻辑清晰,递归函数与状态转换方程的公式一致,不需要考虑计算顺序,程序代码简单,功能可以封装为函数,根据特定需要也有可能不必计算矩阵全部值。
程序说明:(略)
参考链接:(略)
题记:(略)

AC的C++语言程序(记忆化递归)如下:

/* UVA111 History Grading */

#include <bits/stdc++.h>

using namespace std;

const int N = 20;
int a[N + 1], b[N + 1], dp[N + 1][N + 1];

int lcs(int r, int c)
{
    if(dp[r][c] != -1) return dp[r][c];
    else if(r == 0 || c == 0) return dp[r][c] = 0;
    else if(a[r] == b[c]) return dp[r][c] = lcs(r - 1, c - 1) + 1;
    else return dp[r][c] = max(lcs(r, c - 1), lcs(r - 1, c));
}

int main()
{
    int n, x;

    while(~scanf("%d", &n)) {
        for(int i = 1; i <= n; i++) {
            scanf("%d", &x);
            a[x] = i;
        }

        while(~scanf("%d", &x)) {
            b[x] = 1;
            for(int i = 2; i <= n; i++) {
                scanf("%d", &x);
                b[x] = i;
            }

            memset(dp, -1, sizeof(dp));

            printf("%d\n", lcs(n, n));
        }
    }

    return 0;
}

AC的C++语言程序如下:

/* UVA111 History Grading */

#include <bits/stdc++.h>

using namespace std;

const int N = 20;
int a[N + 1], b[N + 1], dp[N + 1][N + 1];

int main()
{
    int n, x;

    while(~scanf("%d", &n)) {
        for(int i = 1; i <= n; i++) {
            scanf("%d", &x);
            a[x] = i;
        }

        while(~scanf("%d", &x)) {
            b[x] = 1;
            for(int i = 2; i <= n; i++) {
                scanf("%d", &x);
                b[x] = i;
            }

            memset(dp, 0, sizeof(dp));
            for(int i = 1; i <= n; i++)
                for(int j = 1; j <= n; j++)
                    if(a[i] == b[j]) dp[i][j] = dp[i - 1][j - 1] + 1;
                    else dp[i][j] = max(dp[i][j - 1], dp[i - 1][j]);

            printf("%d\n", dp[n][n]);
        }
    }

    return 0;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值