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 }

     

     【关键词】:最长上升子序列、最长公共子序列的转化
  • 相关阅读:
    Note/Solution 转置原理 & 多点求值
    Note/Solution 「洛谷 P5158」「模板」多项式快速插值
    Solution 「CTS 2019」「洛谷 P5404」氪金手游
    Solution 「CEOI 2017」「洛谷 P4654」Mousetrap
    Solution Set Border Theory
    Solution Set Stirling 数相关杂题
    Solution 「CEOI 2006」「洛谷 P5974」ANTENNA
    Solution 「ZJOI 2013」「洛谷 P3337」防守战线
    Solution 「CF 923E」Perpetual Subtraction
    KVM虚拟化
  • 原文地址:https://www.cnblogs.com/little-w/p/3525285.html
Copyright © 2011-2022 走看看