题目
陆历川来到了一个神秘的城堡(n*m的矩阵),这个矩阵中有很多的钞票,他们分别位于不同的座标上,现在陆历川位于(1,1),但是他只能
向右或者向下走,最终走到(n,m)终点,但是陆历川无法一下把所有的钞票都拿走,现在他想知道他最少需要几次能把所有的钞票都拿走
输入
N,M,P N,M代表矩阵的大小, P代表有几个座标点有钞票
接下来P行, 每行分别是钞票的座标(X,Y)
输出
一个整数,即次数
样例输入
7 7 7
1 2
1 4
2 4
2 6
4 4
4 7
6 6
输出样例
2
解题思路
首先普及一下最长不上升子序列,例如下面的数字串
6 8 5 4 3 2 9
他的最长不上升子序列就是
6 5 4 3 2 长度为5
我们从最简单的图形考虑
如上图的两个点,我们可以发现无路如何都必须要两次才能完成,由此我们可以推断出,如果有K个点成为这样从右上向左下排开的链,那么取完这K个点至少需要K次。
这里的链不是笼统的一条斜线,是一种抽象的斜线,他是把所有的斜线合并的一条链,合并规则是先把X座标从小到大排序,然后以Y座标为关键字,求最长不上升子序列,这样的链不唯一,下图只画出了其中的一条。
这条链就是我们抽象的斜线,它的长度是4,其余的点只要不属于链,则肯定可以在某一取值时取走。
代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
const int maxn = 1000 + 10 ;
struct point{
int x ;
int y ;
};
point ans[maxn] ;
int len[maxn] , p ;
bool cmp(point a , point b)
{
if(a.x == b. x)
return a.y < b. y ;
return a.x < b. x ;
}
int tofind(int x)
{
int l = 1 , r = p , mid ;
while(l <= r)
{
mid = (l + r) >> 1 ;
if(len[mid] > x)
l = mid + 1;
else
r = mid - 1 ;
}
return l ;
}
int main()
{
int n , m ;
while(scanf("%d %d" , &n , &m) != EOF)
{
memset(ans , 0 , sizeof(ans)) ;
memset(len , 0 , sizeof(len)) ;
scanf("%d" , &p) ;
for(int i = 0 ; i < p ; i++){
scanf("%d %d" , &ans[i].x , &ans[i].y) ;
}
sort(ans , ans + p , cmp) ;
/* for(int i = 0 ; i < p ; i++)
{
printf("ans[%d].y = %d\n" , i , ans[i].y) ;
}*/
int top = 0 ;
len[++top] = ans[0].y ;
for(int i = 1 ; i < p ; i++)
{
if(ans[i].y <= len[top])
{
len[++top] = ans[i]. y ;
}
else
{
int to = tofind(ans[i].y) ;
len[to] = ans[i].y ;
}
}
/* for(int i = 1 ; i <= top ; i++)
{
cout<<"len["<<i<<"] : " << len[i] << endl;
}*/
printf("%d\n" , top) ;
}
return 0 ;
}
/*
7 7 9
2 1
4 1
4 2
6 2
4 4
7 4
3 5
2 6
6 6
*/