题意:n*m的网格,有些格子里可能有宝藏,若站在(x,y),每次只能向(x+1,y)或者(x,y+1)方向走,问最少要走几趟能将网格中的宝物收集完。
分析: 按题目的意思就是只能向右和向下走。如果将宝物的坐标按x轴来从小到大排(x轴相同的按y轴从小到大),那么就可以只考虑y坐标了
,假设有两个位置i,j,i.x<=j.x,当i.y<=j.y时,才有可能收集完i后收集j,所以按x轴排序完后,问题就转化为用最少几个不降子序列可将y轴坐标序列全部涵盖。那就是最长(严格)递减子序列的长度了。
#include <iostream>
#include 
<stdio.h>
#include 
<memory.h>
#include 
<algorithm>
using namespace std;

struct node
{
    
int x,y;
}
a[100010];

int dp[100010],num[100010],b[100010],n,m,p;

int cmp(node p,node q)
{
    
if(p.x==q.x) return p.y<q.y;
    
return p.x<q.x;
}


void solve()    // 求最长递减子序列
{
    
int i,tem,l,r,mid,ans,top;
    b[
1]=num[1]; top=1; dp[1]=1;
    ans
=0;
    
for(i=2;i<=p;i++)
    
{
        
if(num[i]<b[top])
        
{
            b[
++top]=num[i];
            dp[i]
=top;
        }

        
else
        
{
            l
=1; r=top;
            
while(l<=r)
            
{
                mid
=(l+r)>>1;
                
if(b[mid]<=num[i])
                
{
                    tem
=mid;
                    r
=mid-1;
                }

                
else l=mid+1;
            }

            b[tem]
=num[i];
            dp[i]
=tem;
        }

        
if(dp[i]>ans) ans=dp[i];
    }

    printf(
"%d\n",ans);
}


int main()
{
    
int i;
    
while(scanf("%d%d%d",&m,&n,&p)!=EOF)
    
{
        
for(i=1;i<=p;i++)
            scanf(
"%d%d",&a[i].x,&a[i].y);
        sort(a
+1,a+1+p,cmp);
        
for(i=1;i<=p;i++)
            num[i]
=a[i].y;
        solve();
    }

    
return 0;
}