ZOJ 2283 Challenge of Wisdom 数论,Dilworth Theorem,求最长反链 难度:2

Challenge of Wisdom

Time Limit: 2 Seconds      Memory Limit: 32768 KB

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\n",len);
        }
        return 0;
}

  

posted @ 2015-01-31 10:27  雪溯  阅读(503)  评论(0编辑  收藏  举报