码迷,mamicode.com
首页 > 其他好文 > 详细

王子和公主 UVa10635

时间:2016-04-19 22:54:43      阅读:248      评论:0      收藏:0      [点我收藏+]

标签:

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

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

【算法分析】:

这道题读题是关键,然后我们发现需要的是公共的格子,又需要是这个步数最大化,可以想到最长公共子序列的模型。序列长度小于等于62500,最长公共子序列复杂度是n^2,超时。然而可以巧妙的将LCS转化为LIS,使用nlogn的方法求解

 

解题思路:本题是一道经典的题目,巧妙的将LCS问题转化为LIS问题。这种题目的一个特定就是其中一个序列的所有元素均不相同。首先,我们可以对A数组重新编号为{1,2,3,...n},接下来对于B数组的每个元素,替换为A中那个元素的编号,若没有在A中出现,那么直接置0,这样,B数组也变为一个由编号构成的数组,此时我们发现,A数组是一个自然序列,那么只要在B中找到最长上升的子序列,就是和A的最长公共子序列!这就是本题的巧妙之处!而LIS问题有O(N*logN)的解法,因此可以通过本题的数据规模。

 

为什么呢?

A‘中为A中元素的代号 即 它们的顺序号

B‘中为B中元素对应的代号(为了分析方便,这里将B中有而A中没有出现的去掉,等价于置0)

因为去掉了B中有而A中没有出现的,所以B‘中的代号全部对应A中的数

设B‘的一个子集p,那么将p由代号翻译成原来数字后一定是A的一个子集(不过在A中顺序不确定)

B‘的LIS时B‘中一个上升的子集 即 顺序号上升的子集 即 该子集在A中是按从左到右的顺序的

所以它是A与B的公共子序列

又因为LIS最长,所以公共子序列最长 即 最长公共子序列

#include<iostream>
#include<cstring>
#define Max_n 300
using namespace std;

int a[Max_n*Max_n],b[Max_n*Max_n];
int f[Max_n*Max_n];
int n,p,q;
int lable[Max_n*Max_n];

int LIS(){
    f[1]=1;
    int num=0;
    for(int i=2;i<=q+1;i++){
        for(int j=1;j<i;j++) if(b[j]<b[i]){
            f[i]=max(f[i],f[j]+1);
        }
        num=max(num,f[i]);
        //cout<<i<<‘:‘<<f[i]<<endl;
    }
    return num;
}

int main(){
    memset(lable,0,sizeof(lable));
    freopen("27.in","r",stdin);
    
    int x;
    cin>>n>>p>>q;
    for(int i=1;i<=p+1;i++){
        cin>>x;
        if(lable[x]==0){
            lable[x]=i;
        }
        a[i]=lable[x];
        //cout<<a[i]<<‘ ‘;
    }
    //cout<<endl;
    for(int i=1;i<=q+1;i++){
        cin>>x;
        b[i]=lable[x];
        //cout<<b[i]<<‘ ‘;
    }
    //cout<<endl;
    
    int ans=LIS();
    
    cout<<ans;
    
    fclose(stdin);
    return 0;
} 

 

王子和公主 UVa10635

标签:

原文地址:http://www.cnblogs.com/FuTaimeng/p/5410465.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!