程序控

IPPP (Institute of Penniless Peasent-Programmer) Fellow

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: :: 管理 ::
  77 随笔 :: 0 文章 :: 442 评论 :: 0 引用

Time limit: 3.000 seconds

 

Background

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.

 

The Problem

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.

 

The Input

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.

 

The Output

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.

 

Sample Input 1

4
4 2 3 1
1 3 2 4
3 2 1 4
2 3 4 1

 

Sample Output 1

1
2
3

 

Sample Input 2

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 2

6
5
10
9

 

Analysis

注意,给出的序列和一般理解上的出现次序是不同的。比如4 2 3 1,一般理解是第4个事件在第1位,第2个事件在第2位,第1个事件在第4位。但在这道题目,序列的含义是第1个事件在第4位,第2个事件在第2位,第4个事件在第一位。为方便计算,需要对输入的序列进行转换,使数字对号入座。比如一个正确的序列是:

 

正确答案 学生答案 含义
输入的序列 3 1 2 4 9 5 10 6 8 7 2 10 1 3 8 4 9 5 7 6 历史事件发生在第几位
转换后的序列 2 3 1 4 6 8 10 9 5 7 3 1 4 6 8 10 9 5 7 2 发生了第几个历史事件

 

接下来就用转换后的序列进行计算。为了方便的看出学生答案的顺序是否正确,应该按照正确答案与1 2 ... 10的对应关系将学生答案再做一次转换。正确答案中第2个历史件事发生在第1位,那么学生答案中的2应转换为1;即3转换为2,以此类推。学生答案就转换为最终的序列为:

 

编号 1 2 3 4 5 6 7 8 9 10
序列 2 3 4 5 6 7 8 9 10 1

 

显而易见,这个序列的最长有序子串(非连序)的长度为9。要将输入的正确答案序列和学生答案序列都依次做上述转换就显得非常麻烦了,其实正确答案序列是无需转换的。假设正确答案序列为A,学生答案序列为B,则发生在第Bi位的历史事件的最终位置就应该是Ai。这样就可以一次完成全部转换。

接下来就是要找出最长有序子串。因为正确的顺序是由小至大,所以从最后一位开始遍例。依次找出每个数之后(含自身)的最长有序子串长度Mi,然后找最Mi中的最大值即为解。观查下面的序列:

 

编号 1 2 3 4 5 6 7 8 9 10
序列 5 8 3 7 6 1 9 2 10 4

 

算法步骤如下:

  1. 4在第10位,显然M10 = 1;
  2. M9 = 1;
  3. 2在第8位,后面只有4比它大,则M8 = M10 + 1 = 2;M7 = M9 + 1 = 2;
  4. 1在第6位,后面所有数都比它大,但M7到M10中最大值为M7=M8=2,则M6 = M7(或M8) + 1 = 3;
  5. M5 = M7 + 1 = 3;
  6. M4 = M7 + 1 = 3;
  7. M3 = M4(或M5) + 1 = 4;
  8. M2 = M7 + 1 = 3;
  9. M1 = M2(或M5) + 1 = 4;

至此可知,该序列的最长有序子串长度为4。

 

Solution

#include <iostream>
using namespace std;
int main(void) {
	int aTbl[20], aAns[20], aMax[20], nLen, nVar, i = 0;
	for (cin >> nLen; i < nLen && cin >> nVar; aTbl[i++] = nVar);
	while (true) {
		for (i = 0; i < nLen && cin >> nVar; aAns[nVar - 1] = aTbl[i++]);
		if (i != nLen) {
			break;
		}
		memset(aMax, 0, sizeof(aMax));
		for (nVar = 0, i = nLen - 1; i >= 0; --i) {
			for (int j = i + 1; j < nLen; ++j) {
				if (aAns[j] > aAns[i] && aMax[j] > aMax[i]) {
					aMax[i] = aMax[j];
				}
			}
			nVar = ++aMax[i] > nVar ? aMax[i] : nVar;
		}
		cout << nVar << endl;
	}
	return 0;
}
posted on 2010-08-10 15:22  Devymex  阅读(...)  评论(...编辑  收藏