zoukankan      html  css  js  c++  java
  • 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 }

     

     【关键词】:最长上升子序列、最长公共子序列的转化
  • 相关阅读:
    生成XML文件
    webService的发布与调用
    does not contain bitcode ShardSDK等三方库
    IOS在Document目录下创建文件夹、保存、读取、以及删除文件
    判断IOS安装后是否是第一次启动
    OC中使用单例模式
    两个时间(日期)段交集判断方法
    $(document).ready vs. $(window).load
    基于vant上传图片添加水印
    常用的正则校验
  • 原文地址:https://www.cnblogs.com/little-w/p/3525285.html
Copyright © 2011-2022 走看看