UVA 10635 王子和公主

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中只有一个元素。

解决第二个问题:

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

【完整代码】:

  1 #include<iostream>
  2 
  3 #include<stdio.h>
  4 
  5 #include<string.h>
  6 
  7 #include<algorithm>
  8 
  9 #include<stdlib.h>
 10 
 11 #include<math.h>
 12 
 13 #include<queue>
 14 
 15 #include<vector>
 16 
 17 #include<map>
 18 
 19 #define MAXN 62500+10
 20 
 21 #define MAXM 20000+5
 22 
 23 #define oo 9556531
 24 
 25 #define eps 0.000001
 26 
 27 #define PI acos(-1.0)//这个精确度高一些
 28 
 29 #define REP1(i,n) for(int i=0;i<(n);i++)
 30 
 31 #define REP2(i,n) for(int i=1;i<=(n);i++)
 32 
 33 using namespace std;
 34 
 35  
 36 
 37 int A[MAXN];
 38 
 39 int B[MAXN];
 40 
 41 int C[MAXN];//存储转化位置信息
 42 
 43 int n,p,q,cas=0;
 44 
 45 int cnt;
 46 
 47 void builtC()
 48 
 49 {
 50 
 51     cnt=0;
 52 
 53     for(int i=0;i<MAXN;i++) C[i]=0;
 54 
 55     for(int i=0;i<p+1;i++) C[A[i]]=i+1;
 56 
 57     for(int i=0;i<q+1;i++) if (C[B[i]]!=0) A[cnt++]=C[B[i]];
 58 
 59 }
 60 
 61 int d[MAXN],g[MAXN];
 62 
 63 int LIS(int a[], int n)
 64 
 65 {
 66 
 67     int i, j, * b = new int[n + 1], ans = 0;
 68 
 69     b[ans] = - 0x3f3f3f3f;
 70 
 71     for(i = 0; i < n; i ++)
 72 
 73     {
 74 
 75         j = upper_bound(b, b + ans + 1, a[i]) - b;
 76 
 77         if(j > ans)
 78 
 79             b[++ans] = a[i];
 80 
 81         else if(a[i] < b[j])
 82 
 83             b[j] = a[i];
 84 
 85     }
 86 
 87     delete b;
 88 
 89     return ans;
 90 
 91 }
 92 
 93 //}
 94 
 95 int main()
 96 
 97 {
 98 
 99     cin>>cas;
100 
101     for(int k=1;k<=cas;k++)
102 
103     {
104 
105         cin>>n>>p>>q;
106 
107         for(int i=0;i<p+1;i++) cin>>A[i];
108 
109         for(int i=0;i<q+1;i++) cin>>B[i];
110 
111         builtC();
112 
113         cout<<"Case "<<k<<": "<<LIS(A,cnt)<<endl;
114 
115     }
116 
117     return 0;
118 
119 }

 

 【关键词】:最长上升子序列、最长公共子序列的转化
原文地址:https://www.cnblogs.com/little-w/p/3525285.html