题目大意:给出一个由历史事件的发生的先后顺序组成的标准答案,以及若干的试卷答案,要你比对正确的个数,也就是两个序列的最大公共子序列长度。
题目思路:经典模型,状态转移方程:A[i]==B[i]时,dp(x,y) = dp(x-1,y-1)+1,否则dp(x,y) = max(dp(x-1,y),dp(x,y-1))
题目坑点:并不是要你求给你的两个序列的最大公共子序列长度。而是要先转化,以
3 1 2 4 9 5 10 6 8 7为例,意思是第一个事件第三个发生,第二个事件第一个发生,那重排以后的序列的第一项就应该是2,即代表第一个发生的事件的编号。
代码如下:可以改进的地方有:将输入与转化的过程另外写一个函数。
#include <iostream> #include <stdio.h> #include <fstream> #include <iomanip> #include <cmath> #include <string> #include <string.h> #include <sstream> #include <cctype> #include <climits> #include <set> #include <map> #include <queue> #include <vector> #include <iterator> #include <algorithm> #include <stack> #include <functional> /*int类型最大值INT_MAX,short最大值为SHORT_MAX long long最大值为LONG_LONG_MAX*/ //cout << "OK" << endl; #define _clr(x) memset(x,-1,sizeof(x)) using namespace std; const int INF = INT_MAX; const double eps = 1e-8; const double EULER = 0.577215664901532860; const double PI = 3.1415926535897932384626; const double E = 2.71828182845904523536028; typedef long long LL; int n,a[100],b[100],ans[100],ans2[100],res[100][100]; int dp(int x,int y) { if(x == -1||y == -1) return 0; if(res[x][y] != -1) return res[x][y]; if(a[x] == ans[y]) return res[x][y] = dp(x-1,y-1)+1; else return res[x][y] = max(dp(x-1,y),dp(x,y-1)); } int main() { //freopen("sample.in", "r", stdin); //freopen("sample.out", "w", stdout); cin >> n; for(int i = 0;i<n;i++) cin >> b[i]; for(int i = 0;i<n;i++) a[b[i]-1] = i+1; //for(int i = 0;i<n;i++)cout << a[i] << " "; //cout << endl; while(cin >> ans2[0]) { _clr(res); for(int i = 1;i<n;i++) cin >> ans2[i]; for(int i = 0;i<n;i++) ans[ans2[i]-1] = i+1; cout << dp(n-1,n-1) << endl; } //fclose(stdin); //fclose(stdout); return 0; }