題目
陸歷川來到了一個神祕的城堡(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
*/