Background
"Then, I want to know whether you're a wise boy!"
Problem
"I have a great deal of lands. They're divided into N*M grids (N, M <= 1,000,000,000). When you are in (x, y), you may move into (x+1, y) or (x, y+1). I have P (P <= 100,000) treasures in the lands; each time, you can pick up anything you like."
"Now, I'll give you a map of my treasures; tell me, wise boy, how many times you need to pick up all the treasures?"
Input
This problem contains multiple test cases.
Each test case begins with 3 integers N, M and P. then followed by P lines, each lines contains 2 numbers: x, y, representing the location of a treasure.
Output
For each test case, output the minimum times I need.
Sample Input
7 7 7
1 2
1 4
2 4
2 6
4 4
4 7
6 6
Sample Output
2
Contest: A Great Beloved and My Gate to Freedom
There is a cx, there is a love_cx.
从左上角出发,对于
OO
OX
这种右方和下方同时存在的情况,无论是先去右方还是先去下方,都必然有一个是新开始点,+1次数,所以可以直接以x坐标为主,y坐标为辅排序,这个时候直接选定决策优先向右走即可,次数不会发生变化
但是直接模拟会超时,需要更普遍的规律,明显对于上图,有排序是(x,y),(x,y+1),(x+1,y)也就是说y会出现逆序,每出现一次逆序,有两种可能,第一种是这个逆序之前已经被拆分了(某个点已经被走过),另一种是需要多走一次,找到最长的逆序,这就是答案
下面是理论依据
________________________________________________________________________________
转载自 http://blog.csdn.net/xuzengqiang/article/details/7266034
偏序的概念:
设A是一个非空集,P是A上的一个关系,若关系P是自反的、反对称的、和传递的,则称P是集合A上的偏序关系。
即P适合下列条件:
(1)对任意的a∈A,(a,a)∈P;
(2)若(a,b)∈P且(b,a)∈P,则a=b;
(3)若(a,b)∈P,(b,c)∈P,则(a,c)∈P,则称P是A上的一个偏序关系。带偏序关系的集合A称为偏序集或半序集。
若P是A上的一个偏序关系,我们用a≤b来表示(a,b)∈P。
比方说:(A,≤)是偏序集,A={1,2,3},偏序≤在A上的大于等于关系。则有:≤={<3,3>,<3,2>,<3,1>,<2,2>,<2,1>,<1,1>},则有3≤2,2≤2,2≤1....
举如下例子说明偏序关系:
1、实数集上的小于等于关系是一个偏序关系。
2、设S是集合,P(S)是S的所有子集构成的集合,定义P(S)中两个元素A≤B当且仅当A是B的子集,即A包含于B,则P(S)在这个关系下成为偏序集。
3、设N是正整数集,定义m≤n当且仅当m能整除n,不难验证这是一个偏序关系。注意它不同于N上的自然序关系。
在Partially order set(偏序集)有一个非常NX的定理叫Dilworth Theorem。偏序集的定义是
偏序是在集合X上的二元关系≤(这只是个抽象符号,不是“小于或等于”),它满足自反性、反对称性和传递性。即,对于X中的任意元素a,b和c,有:
自反性:a≤a;
反对称性:如果a≤b且b≤a,则有a=b;
传递性:如果a≤b且b≤c,则a≤c 。
带有偏序关系的集合称为偏序集。
令(X,≤)是一个偏序集,对于集合中的两个元素a、b,如果有a≤b或者b≤a,则称a和b是可比的,否则a和b不可比。
例:(A,≤)是偏序集,其中A={1,2,3,4,5},其中≤是整除关系,那么对任意的x∈p都有1≤x,所以1和1,2,3,4,5都是可比的,但是2不能整除3,且3不能整除2,所以2和3是不可比的。
在X中,对于元素a,如果任意元素b,由b≤a得出b=a,则称a为极小元。
一个反链A是X的一个子集,它的任意两个元素都不能进行比较。
一个链C是X的一个子集,它的任意两个元素都可比。
下面是两个重要定理:
定理1 令(X,≤)是一个有限偏序集,并令r是其最大链的大小。则X可以被划分成r个但不能再少的反链。
其对偶定理称为Dilworth定理:
定理2 令(X,≤)是一个有限偏序集,并令m是反链的最大的大小。则X可以被划分成m个但不能再少的链。
证明:设p为最少反链个数
(1)先证明X不能划分成小于r个反链。由于r是最大链C的大小,C中任两个元素都可比,因此C中任两个元素都不能属于同一反链。所以p>=r。
(2)设X1=X,A1是X1中的极小元的集合。从X1中删除A1得到X2。注意到对于X2中任意元素a2,必存在X1中的元素a1,使得a1<=a2。令A2是X2中极小元的集合,从X2中删除A2得到X3……最终,会有一个Xk非空而X(k+1)为空。于是A1,A2,...,Ak就是X的反链的划分,同时存在链a1<=a2<=...<=ak,其中ai在Ai内。由于r是最长链大小,因此r>=k。由于X被划分成了k个反链,因此r>=k>=p。因此r=p,定理1得证。
搞清楚了反链和链的定义,就能够很好的从Hasse Diagram中得到理解。链就是从纵向的角度看 Hasse Diagram ,反链是从横向的角度看Hasse Diagram。
定理一,就是至少有r行构成反链关系。
定理二,就是至少有m列构成链关系。
___________________________________________________
如何找到最长反链?
偏序关系是小于等于,反链肯定满足严格递减,也就是大于关系,但是这个反链是位置不连续的,不能直接简单靠dp求,可以先从前面出发,把递增数列保存在数组中,如果新值小于这个数列最小值,那么就放在最末尾,也就是递增数列的长度增加,否则,二分找到可以放置的位置,这个位置上的数字小于新值,替换之,以使这个数列更优,依然能保证更新时较小的值位置后于较大的值
#include <cstdio> #include <algorithm> using namespace std; const int maxn=1e6+5; int n,m,p; struct pnt{ int x,y; pnt(){x=y=0;} pnt(int x,int y){this->x=x;this->y=y;} bool operator < (pnt p2)const {return x!=p2.x?x<p2.x:y<p2.y;} bool operator > (pnt p2)const {return x!=p2.x?x>p2.x:y>p2.y;} pnt operator = (const pnt p2){x=p2.x;y=p2.y;return *this;} }; pnt pt[maxn]; int dp[maxn],len; void replace(int x){ int l=0,r=len; while(r>l){ int m=(l+r)>>1; if(dp[m]>x){ l=m+1; } else { r=m; } } if(dp[l]<x&&l<len)dp[l]=x; } int main(){ while(scanf("%d%d%d",&n,&m,&p)==3){ len=0; for(int i=0;i<p;i++){ scanf("%d%d",&pt[i].x,&pt[i].y); } sort(pt,pt+p); if(p>0)dp[len++]=pt[0].y; for(int i=1;i<p;i++){ if(dp[len-1]>pt[i].y){ dp[len++]=pt[i].y; } else { replace(pt[i].y); } } printf("%d ",len); } return 0; }