题意:宝藏在一些点中,只能从(0,0)出发,每次只能向右(x+1,y)或是向上走(x,y+1)。问要走几趟才能取完宝藏。
解法:按x,y分别为第一二关键字排序,那么一趟下来,y坐标是个非递减序列。然后转化成问y方向能由最少为多少的非递减序列个数组成。这个等效于求严格递减序列的长度。即nlogn求最长严格递减序列长度即可。
代码:
/******************************************************
* @author:xiefubao
*******************************************************/
#pragma comment(linker, "/STACK:102400000,102400000")
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <queue>
#include <vector>
#include <algorithm>
#include <cmath>
#include <map>
#include <set>
#include <stack>
#include <string.h>
//freopen ("in.txt" , "r" , stdin);
using namespace std;
#define eps 1e-8
#define zero(_) (abs(_)<=eps)
const double pi=acos(-1.0);
typedef long long LL;
const int Max=100010;
const LL INF=0x3FFFFFFF;
int N, M ,P;
struct point
{
int x,y;
} points[Max];
int num[Max];
bool operator<(const point& a,const point& b)
{
if(a.x==b.x) return a.y<b.y;
return a.x<b.x;
}
struct cmp
{
int operator()(const int& a,const int& b)
{
return a>b;
}
};
int up[Max];//up[j]表示从num[0]到num[j],以num[j]结尾的最长升序长度
int D[Max];//辅助数组
int getLIS(int num[],int n)//up[j]表示从num[0]到num[j],以num[j]结尾的最长升序长度
{
int last=0;
int ans=0;
for(int i=0; i<n; i++)
{
up[i]=lower_bound(D,D+last,num[i],cmp())-D+1;//lower_bound计算的是严格升序 upper_bound计算的是非严格升序(可以相等)
if(up[i]>last) D[last = up[i]]=num[i];
D[up[i]-1]=num[i];//更新D[k]为最小的
ans=max(ans,up[i]);
}
return ans;
}
bool operator==(const point& a,const point& b)
{
if(!(a<b)&&!(b<a))
return true;
return false;
}
int main()
{
while(scanf("%d%d%d",&N,&M,&P)==3)
{
for(int i=0; i<P; i++)
{
scanf("%d%d",&points[i].x,&points[i].y);
}
//cout<<P<<endl;
sort(points,points+P);
for(int i=0; i<P; i++)
num[i]=points[i].y;
cout<<getLIS(num,P)<<endl;
}
return 0;
}
/*
100 100 8
0 1
0 2
1 0
1 1
1 2
2 0
2 1
2 2
2 5 8
1 4 7
0 3 6
*/