题目:在一个n*n的棋盘上,格子标号1~n*n,现在有两个人从1跳到n*n(不走重复点),
现在要求去掉最少的中间点,使得路径是一样的。
分析:dp,LIS,LCS。问题是求最大公共子序列,数据较大需要O(nlgn)算法。
发现题目中的数据是不重复的,所以可以转化成最大上升子序列;
记录序列1中每个元素对应的顺序,将序列2中的元素转化成对应序列1中的顺序标号;
那么,新构成的序列2中递增的序列即为序列1中的先后顺序,所以求出它的LIS即可。
说明:╮(╯▽╰)╭。
#include <algorithm> #include <iostream> #include <cstdlib> #include <cstring> #include <cstdio> #include <cmath> using namespace std; int prince[62505]; int visit[62505]; int princess[62505]; int MUQ[62505]; int lis(int n, int* Q) { int l,r,m,i,tail = 0; for (MUQ[++ tail] = Q[1],i = 2; i <= n; ++ i) { if (MUQ[tail] < Q[i]) { MUQ[++ tail] = Q[i]; continue; } for (m=((r=tail)+(l=1)>>1); l < r; m=(l+r)>>1) if (MUQ[m] < Q[i]) l = m+1; else r = m; MUQ[m] = Q[i]; } return tail; } int main() { int T,n,p,q,k; while (~scanf("%d",&T)) for (int t = 1; t <= T; ++ t) { scanf("%d%d%d",&n,&p,&q); memset(visit, 0, sizeof(visit)); for (int i = 0; i <= p; ++ i) { scanf("%d",&k); visit[k] = 1; prince[k] = i+1; } int count = 0; for (int i = 0; i <= q; ++ i) { scanf("%d",&k); if (visit[k]) princess[++ count] = prince[k]; } printf("Case %d: %d\n",t,lis(count, princess)); } return 0; }
时间: 2024-10-03 13:40:01