楼兰宝藏

楼兰宝藏(Treasure_map.cpp/c/pas)  zju2283

【题目描述】

在魔法世界的历史上,楼兰是个充满了神秘色彩的名字。那座昔日绿草遍地人往如织的繁荣古城──楼兰,在公元4 世纪以后,却突然神秘地消失了,留下的只是 “城郭巍然,人物断绝”的不毛之地和难解之谜。

不过著名冒险家席慕蓉在一次探险中发现,原来被沙丘掩埋的楼兰古国地下,埋藏着不计其数的宝藏。

简单说来,就是在一张 N×M的地图,地图上画有P个宝藏(1 ≤ N,M ≤10000000000,P ≤100000),每次当探险者坐标为 (x,y)时,他可以向 (x+1,y)或 (x,y+1)移动一格,问最少要多少次才能拣起所有的宝藏(每次走到最后一步时,会自动传送回左上角位置)。


【输入格式】

第一行有三个整数,分别为N,M,P。余下P行分别为每个宝藏的X、Y坐标。


【输出格式】

一个整数,即次数。


【输入样例】

7 7 7

1 2

1 4

2 4

2 6

4 4

4 7

6 6


【输出样例】

2


【参考代码】

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm> 
using namespace std;

int a[100001],b[100001],link[100001],v[100001],p[100001],tot//v[]用来统计记录序列元素下标

void swap(int &a,int &b)//交换a与b当前的值
{
    int t;
    t=a;
	a=b;
	b=t;
}

void init(int n)//初始化,将数组倒叙 
{
    int t,i;
    for(i=1;i<=n;i++)
    {
	    t=b[i];
		b[i]=b[n-i+1];
		b[n-i+1]=t;
	}
}

int find(int key)//二分查找下标
{
    int mid,L,R;
    L=1;
	R=tot;
    while(L<=R)
    {
        mid=(L+R)/2;
        if(b[v[mid]]<key)
            L=mid+1;
        else
            R=mid-1;
    }
    return L-1;
}

void sort(int L,int R)
{
    if(L>=R)  
        return ;
    int i,j,k;
    k=a[(L+R)/2];
    i=L;
	j=R;
    while(i<=j)
    {
        while(a[i]<k)
		    i++;
        while(a[j]>k)
		    j--;
        if(i<=j)
        {
            swap(a[i++],a[j--]);
            swap(b[i++],b[j--]);             
        }
    }
    sort(L,j);
    sort(i,R);
}

int main()
{
    //freopen("Treasure_map.in","r",stdin);
    //freopen("Treasure_map.out","w",stdout);  
    int i,j,n,m,k,L;
    cin>>n>>m>>k;//有一个m*n的矩阵,有 k个宝藏 
    for(i=1;i<=k;i++)
        cin>>a[i]>>b[i],p[i]=i;//宝藏的坐标a为横坐标,b为纵坐标 
    sort(1,n);//对横坐标进行排序, 然后以之为权找最长不上升子序列 
    init(n);
    tot=1;
	v[tot]=1;
	link[1]=p[1];
    //tot指最长不上升序列的长度,p[]表示序列的下标,link[]表示连接 
    for(i=2;i<=k;i++)
    {
        if(b[p[i]]<=b[v[tot]])
        {
            tot++;
            v[tot]=p[i];
            link[p[i]]=v[tot-1];
        }
        else
        {
            L=find(b[p[i]]);
            v[L+1]=p[i];
            link[p[i]]=v[L];
        }
    }
    cout<<tot<<endl;//只需打印长度 
    return 0;
}
最长不下降子序列
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值