poj 3636 Dilworth定理(嵌套方形娃娃) Dilworth定理详细讲解

参考:http://blog.youkuaiyun.com/acdreamers/article/details/7626671

Dilworth定理:对于一个偏序集,最少链划分等于最长反链长度。
Dilworth定理的对偶定理:对于一个偏序集,其最少反链划分数等于其最长链的长度。

也就是说把一个数列划分成最少的最长不升子序列的数目就等于这个数列的最长上升子序列的长度。

下面来说说这个定理是怎么来的:

偏序集的定义:偏序是在集合X上的二元关系≤(这只是个抽象符号,不是“小于或等于”,它满足自反性、反对称性和传递
性)。即,对于X中的任意元素a,b和c,有:

(1)自反性:a≤a;
(2)反对称性:如果a≤b且b≤a,则有a=b;
(3)传递性:如果a≤b且b≤c,则a≤c 。

带有偏序关系的集合称为偏序集。
令(X,≤)是一个偏序集,对于集合中的两个元素a、b,如果有a≤b或者b≤a,则称a和b是可比的,否则a和b不可比。
在这个例子(反链)中元素Ri<=Rj是指(i<=j) and (ai>=aj)

一个反链A是X的一个子集,它的任意两个元素都不能进行比较。
一个链C是X的一个子集,它的任意两个元素都可比。

【定理】
在X中,对于元素a,如果任意元素b,都有a≤b,则称a为极小元。
定理1:令(X,≤)是一个有限偏序集,并令r是其最大链的大小。则X可以被划分成r个但不能再少的反链。

其对偶定理称为Dilworth定理:
令(X,≤)是一个有限偏序集,并令m是反链的最大的大小。则X可以被划分成m个但不能再少的链。
虽然这两个定理内容相似,但第一个定理证明要简单一些。此处就只证明定理1。

证明:设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非空而Xk+1为空。于是A1,A2,…,Ak就是X的
反链的划分,同时存在链a1<=a2<=…<=ak,其中ai在Ai内。由于r是最长链大小,因此r>=k。由于X被划分成了k个反链,因此
r>=k>=p。
(3)因此r=p,定理1得证。

【解决】
要求最少的覆盖,按照Dilworth定理
最少链划分 = 最长反链长度

题意:给定一系列方形,已知其中一个方形的长和宽都小于另一个方形的时候,这两个方形可以嵌套,若干个方形的嵌套成为一个嵌套组。问最少用多少个嵌套组可以将这些方形全部处理完毕。

思路:就是Dilworth的应用。注意排序的时候第一维从小到大,如果相同,第二维从大到小。然后求第二维的最长不增子序列长度(注意二分查找时的区别)。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define N 40005
int T,n,m;
struct node{
    int a,b;
}p[N];
int dp[N];
int cmp(const void *a,const void *b){
    if((*(struct node *)a).a == (*(struct node *)b).a)
        return (*(struct node *)b).b - (*(struct node *)a).b;
    return (*(struct node *)a).a - (*(struct node *)b).a;
}
int find(int x,int len){
    int low,high,mid;
    low = 0;
    high = len;
    while(low <= high){
        mid = (low+high)>>1;
        if(dp[mid] < x)
            high = mid-1;
        else
            low = mid+1;
    }
    return low;
}
int main(){
    scanf("%d",&T);
    while(T--){
        int i,j,len = 0;
        scanf("%d",&n);
        memset(dp,0,sizeof(dp));
        for(i = 0;i<n;i++)
            scanf("%d %d",&p[i].a,&p[i].b);
        qsort(p,n,sizeof(struct node),cmp);
        
        for(i = 0;i<n;i++){
            j = find(p[i].b,len);
            if(j == len+1)
                dp[++len] = p[i].b;
            else
                dp[j] = p[i].b;
        }
        printf("%d\n",len+1);
    }
        
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值