zoukankan      html  css  js  c++  java
  • 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
    ",len);
            }
            return 0;
    }
    

      

  • 相关阅读:
    在ASP.Net和IIS中删除不必要的HTTP响应头
    java合并多个word 2007 文档 基于docx4j
    [转]怎样与 CORS 和 cookie 打交道
    css 设置div半透明 悬浮在页面底部 不随滚动条滚动
    [转]理解Vuex的辅助函数mapState, mapActions, mapMutations用法
    [转]Vue中用props给data赋初始值遇到的问题解决
    [转]import xxx from 和 import {xxx} from的区别
    [转]详解vue父组件传递props异步数据到子组件的问题
    [转]js判断数据类型的四种方法
    [转]iview的render函数用法
  • 原文地址:https://www.cnblogs.com/xuesu/p/4263694.html
Copyright © 2011-2022 走看看