问题描述
/*寂静的星期三…………
Nicole半夜去机房刷完题后,突然发现tech的U盘没有带走……
果然,上面有“动物世界”“入党申请书”“毛主席选集”“金刚葫芦娃”“英语听力材料”“走进科学”等很可疑的压缩包,但是狡猾的tech都设了密码。
历尽千辛万苦,Nicole发现一个文本文档,里面有很多数。*/前面可忽视
确切的说,一共有N行,每一行有M个数字。这些数字都是1到M的一个排列。
只是这些数全部都是有规律的,最后的密码肯定是这M列数字里面的某一列。而这一列的序号,是这N行数字的最长上升公共子序列的长度!!当然,你只需要告诉Nicole这个长度即可。
输入格式
第一行2个空格隔开的正整数N和M
接下来N行,每行M个数,保证这M个数全部是1~M的一个排列。
输出格式
一个数,如题目所述。
样例输入
2 7
1 2 3 5 7 6 4
1 7 2 6 3 4 5
样例输出
4
提示
数据范围:
对于100%的数据,有N<=100,M<=200
说明:
1 2 3 4和1 2 3 5均可。
还记得怎么求两个序列的最长上升公共子序列吗?
如果不记得:
停🤚!你先学会求两个序列的最长上升公共子序列(如果懂请忽略)
当你懂之后
你一定会想到:不就是多几个序列吗?
对于100%的数据,有N<=100,M<=200
n <= 100,你肯定开不出100维的数组吧
于是你需要换思路。
首先,你要注意到一个与其他题不一样的一点:
保证这M个数全部是1~M的一个排列
“排列” 是什么意思?
指的是一个长度为n的序列由1~n这些数组成,每个数都出现一次。
比如n = 3
(1,2,3),(1,3,2),(2,1,3),(2,3,1),(3,1,2),(3,2,1)
这些就是n个数1~n排列
而(1,1,2),(3,3,2)就不是
所以,题目保证
• 每个序列都是1到M的排列!
• 每个数在每个序列中只出现一次!
然后,我们照常设定状态:f[x]表示以x为结尾的最长上升公共子序列当长度
状态转移if (y <= x - 1) f[x] = f[y] + 1 (即每个序列中y都在x左边)
•既然要确定方位,我们就要再开一个数组p[i][x],表示在第i个序列中值为x的位置
可得无论在哪个序列中,在y <= x - 1的情况下,p[i][y] 必须小于 p[i][x]
(why?)
!请仔细思考5分钟 !
因为
保证这M个数全部是1~M的一个排列
每个数字仅,也必须出现一次,所以当y < x 但p[i][y] >= p[i][x],也就是y在i序列中在x之后时,x之前就不会有y,这样以x为结尾的n个序列的最长上升公共子序列就不成立
举个例子:
n = 3;(共3个序列)m = 4(长度为4)
分别为:
1,3,2,4
1,4,2,3
4,2,3,1
假设x为此时的2,y = 1;在第三个序列中,1在2之后,很明显以2结尾的最长上升公共子序列就不能包含1
于是,你要循环判断,是不是每个序列都满足条件
for (int y = x - 1; y >= 1; y--) {
if (f[x] <= f[y]) {
bool flag = 1;
for (int i = 1; i <= n; i++) {
if (p[i][y] > p[i][x]) {
flag = 0;
}
}
if (flag) {
f[x] = f[y] + 1;
}
}
}
(当没有y满足相对应的x时,f[x] = 1,所以可以在循环开头初始化
f[x] = 1;
)
最终答案 ans = max(ans, f[x])
那么,时间复杂度呢?
O(n^2*m),没有问题
想要完整代码??
没门儿!!
THE END