POJ 3636 POJ 1065 (Dilworth定理)

偏序集的两个定理:
定理1) 令(X,≤)是一个有限偏序集,并令r是其最大链的大小。则X可以被划分成r个但不能再少的反链。
其对偶定理称为Dilworth定理:
定理2) 令(X,≤)是一个有限偏序集,并令m是反链的最大的大小。则X可以被划分成m个但不能再少的链。
 即:链的最少划分数=反链的最长长度


Problem: 3636

排序: 第一关键字升序, 第二关键字降序。之后按照第二关键字求最长非递增子序列的长度就是答案.

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include <cmath>
#include <queue>
#include <map>
#include <set>
using namespace std; 
#define INF 1000000000
//typedef __int64 LL; 
#define N 21111
int n, sta[N], tot; 
struct node {
    int w, h; 
}p[N]; 
int cmp(node a, node b) {
    if(a.w == b.w) return a.h > b.h; 
    return a.w < b.w; 
}
int search(int x, int l , int r) {
    int ret; 
    while(l <= r) {
        int m = (l + r) >>1; 
        if(sta[m] < x) ret = m, r = m - 1; 
        else l = m + 1; 
    }
    return ret; 
}
int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin); 
#endif // ONLINE_JUDGE
    int t; 
    scanf("%d", &t); 
    while(t--) {
        scanf("%d", &n); 
        for(int i = 1;i <= n; i++) {
            scanf("%d%d", &p[i].w, &p[i].h); 
        }
        sort(p+1, p+1+n, cmp); 
        tot = 0; 
        for(int i = 1; i <= n; i++) {
            int now = p[i].h; 
            if( tot == 0 || sta[tot] >= now) {
                tot ++; 
                sta[tot] = now; 
            }
            else {
                int id = search(now, 1, tot); 
                sta[id] = now; 
            }
        }
        cout<<tot<<endl; 
    }
    
    return 0; 
}


Problem: 1065

排序:第一关键字升序,第二关键字也是升序。求排序后第二关键字的最长严格递减序列的长度即可。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include <cmath>
#include <queue>
#include <map>
#include <set>
using namespace std; 
#define INF 1000000000
//typedef __int64 LL; 
#define N 21111
int n, sta[N], tot; 
struct node {
    int w, h; 
}p[N]; 
int cmp(node a, node b) {
    if(a.w == b.w) return a.h < b.h; 
    return a.w < b.w; 
}
int search(int x, int l , int r) {
    int ret; 
    while(l <= r) {
        int m = (l + r) >>1; 
        if(sta[m] <= x) ret = m, r = m - 1; 
        else l = m + 1; 
    }
    return ret; 
}
int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin); 
#endif // ONLINE_JUDGE
    int t; 
    scanf("%d", &t); 
    while(t--) {
        scanf("%d", &n); 
        for(int i = 1;i <= n; i++) {
            scanf("%d%d", &p[i].w, &p[i].h); 
        }
        sort(p+1, p+1+n, cmp); 
        tot = 0; 
        for(int i = 1; i <= n; i++) {
            int now = p[i].h; 
            if( tot == 0 || sta[tot] > now) {
                tot ++; 
                sta[tot] = now; 
            }
            else {
                int id = search(now, 1, tot); 
                sta[id] = now; 
            }
        }
        cout<<tot<<endl; 
    }
    
    return 0; 
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值