您的位置:首页 > 其它

UVA 10635 王子和公主

2014-01-18 17:12 337 查看
UVA 10635

【题目描述】:王子和公主

一个王子和公主在n*n的格子中行走,这些格子是有1....n^2的编号的。现在给定p+1个数,再给定q+1个数,公主和王子可以选择其中某些格子行走,求他们最多能走几个相同的格子。

【算法分析】:

这道题读题是关键,然后我们发现需要的是公共的格子,又需要是这个步数最大化,可以想到最长公共子序列的模型。序列长度小于等于62500,最长公共子序列复杂度是n^2,超时,书上提供了把公共子序列退化到最长上升子序列的方法。以第一个系列为参照,编号1.....p+1,因为格子的数字是不重复的,且最大编号是62500,空间上满足。给第二个序列重新标号,求最长上升子序列就可以了。代码中的LIS方法是nlg2(n)的。

【总结】:首先要知道这个退化模型的局限性:1、数字不重复;2、标号小于等于62500(数字较小可存储)。

解决第一个问题:

举例: 7 4 1 1 6 7 3

1 2 1 7 4 2 7

理想标号: 1 2 3 4 5 6 7

3 0 4 1 2 0 6

我们对每一个重复的数字,例如1,在1这个节点上用MAP<int,vector>,把3,4的序列用vector按顺序存储即可,读数的时候,按照从小到大的顺序标号即可。因为标号本身是从小到大的,所以保证解的最大化。那么到这里,我们统一用map存储好了,出现一次的数字,在vector中只有一个元素。

解决第二个问题:

把大数统一用哈希表存储就可以了,同样能满足编号不重复。

【完整代码】:

#include<iostream>

#include<stdio.h>

#include<string.h>

#include<algorithm>

#include<stdlib.h>

#include<math.h>

#include<queue>

#include<vector>

#include<map>

#define MAXN 62500+10

#define MAXM 20000+5

#define oo 9556531

#define eps 0.000001

#define PI acos(-1.0)//这个精确度高一些

#define REP1(i,n) for(int i=0;i<(n);i++)

#define REP2(i,n) for(int i=1;i<=(n);i++)

using namespace std;

int A[MAXN];

int B[MAXN];

int C[MAXN];//存储转化位置信息

int n,p,q,cas=0;

int cnt;

void builtC()

{

cnt=0;

for(int i=0;i<MAXN;i++) C[i]=0;

for(int i=0;i<p+1;i++) C[A[i]]=i+1;

for(int i=0;i<q+1;i++) if (C[B[i]]!=0) A[cnt++]=C[B[i]];

}

int d[MAXN],g[MAXN];

int LIS(int a[], int n)

{

int i, j, * b = new int[n + 1], ans = 0;

b[ans] = - 0x3f3f3f3f;

for(i = 0; i < n; i ++)

{

j = upper_bound(b, b + ans + 1, a[i]) - b;

if(j > ans)

b[++ans] = a[i];

else if(a[i] < b[j])

b[j] = a[i];

}

delete b;

return ans;

}

//}

int main()

{

cin>>cas;

for(int k=1;k<=cas;k++)

{

cin>>n>>p>>q;

for(int i=0;i<p+1;i++) cin>>A[i];

for(int i=0;i<q+1;i++) cin>>B[i];

builtC();

cout<<"Case "<<k<<": "<<LIS(A,cnt)<<endl;

}

return 0;

}


【关键词】:最长上升子序列、最长公共子序列的转化
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: