Dilworth定理

今天早上准备看一波uestc的dp,看到第一道例题的时候发现我竟然不会QAQ,心想清早看的第一题我都不会,甚是郁闷,然后又去百度百度……发现了一个Dilworth定理,然后一直怼一直怼。

结论:对于一个偏序集,最少的chain的个数等于最长antichain的长度,最少的antichain的个数等于最长chain的长度。

比如对于一个二元组,定义偏序关系"≤",当且仅当(a.i < b.i) && (a.j < b.j)时,a 与 b可比,但是会发现有些二元组是没法比较的,称之为偏序集。

与她相对的东西叫做全序集,就是任意两个元素都可以比较,还有就是良序集,有最小元素,比如正整数就是一个良序集。

看了半天QAQ,依然没有看懂证明,证明好久懂了,再回来补吧,接下来我讲一讲这个定理的实际的应用

一、

codevs 1044 导弹拦截:

题意:依次给出每个导弹飞来的高度,有一种反导弹装置可以将导弹击毁,但是中途过程中,反导弹装置的高度不能升高,求某一台装置最多击落多少个导弹?请问至少需要多少台装置可以拦截所有导弹?

题解:

chain : xi ≤ xj 当且仅当 (i <= j && h[i] >= h[j])

antichain : (h[i] < h[j] && i <= j) || (h[i] >= h[j] && i > j)

如果按照i <= j 排序,那么antichain中所有的元素h[i] < h[j],现在的问题就是求这个串最长上升子序列的长度。

代码:

#include <bits/stdc++.h>
using namespace std;

const int N = 1e6 + 7;
int x[N], n = 1, d[N], ans1, ans2;

int main () {
	while (cin >> x[n]) n++;
	--n;
	memset (d, 127, sizeof d);
	for (int i = n; i >= 1; --i) {
		int p = upper_bound (d + 1, d + 1 + n, x[i]) - d;
		ans1 = max (ans1, p);
		d[p] = x[i];
	}
	memset (d, 127, sizeof d);
	for (int i = 1; i <= n; ++i) {
		int p = lower_bound (d + 1, d + 1 + n, x[i]) - d;
		ans2 = max (ans2, p);
		d[p] = x[i];
	}
	cout << ans1 << endl << ans2;
	return 0;
}

  

二、

POJ 1065 Wooden Sticks

题意:有n个棍子,每个棍子都有长度和质量,现在有一台机器来处理这些棍子,机器开启需要一个单位的时间,但是比如现在处理到了第 i 根棍子,如果第i + 1 根棍子的长度和质量都大于等于第i根棍子那么将不会消耗时间,求处理完这些棍子的最少时间。

题解:

chain : xi ≤ xj 当且仅当 (xi.m <= xj.m && xi.w <= xj.w)

antichain : (xi.m <= xj.m && xi.w > xj.w) || (xi.m > xj.m && xi.w <= xj.w)

如果按照x.m从小到大排序,那么就应该求最长下降子序列,但是在m相等的情况下要使x.w 按照从小到大的顺序来排,因为这样才能在求子序列的时候避免错误情况。

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int N = 1e5 + 7;
int kase, n, d[N];

struct node {int a, b;} x[N];

bool cmp (node x, node y) {
	if (x.a == y.a) return x.b < y.b;
	return x.a < y.a;
}

int main () {
	scanf ("%d", &kase);
	while (kase--) {
		scanf ("%d", &n);
		for (int i = 1; i <= n; ++i)
			scanf ("%d%d", &x[i].a, &x[i].b);
		sort (x + 1, x + 1 + n, cmp);
		memset (d, 127, sizeof d);
		int ans = 0;
		for (int i = n; i >= 1; --i) {
			int p = lower_bound (d + 1, d + 1 + n, x[i].b) - d;
			ans = max (ans, p);
			d[p] = x[i].b;
		}
		cout << ans << endl;
	}
	return 0;
}

  

poj 3636 Nested Dolls

题意:有n个矩形,如果一个矩形的长宽都小于另一个矩形的长宽,那么这两个矩形可以嵌套在一起,问最少需要几个嵌套组合才能匹配完所有的矩形?

题解:

chain : xi ≤ xj 当且仅当 (xi.l < xj.l && xi.w < xj.w)

antichain :  (xi.l <= xj.l && xi.w >= xj.w) || (xi.l >= xj.l && xi.w <= xj.w)

如果按照x.l从小到大排序,那么就是求关于x.w的最长不上升子序列,但是注意的是当x.l相等的时候,要按照w从大到小排序。

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int N = 1e5 + 7;
int kase, n, d[N];

struct node {int a, b;} x[N];

bool cmp (node x, node y) {
	return (x.a < y.a) || (x.a == y.a && x.b > y.b);
}

int main () {
	scanf ("%d", &kase);
	while (kase--) {
		scanf ("%d", &n);
		for (int i = 1; i <= n; ++i)
			scanf ("%d%d", &x[i].a, &x[i].b);
		sort (x + 1, x + 1 + n, cmp);
		memset (d, 127, sizeof d);
		int ans = 0;
		for (int i = n; i >= 1; --i) {
			int p = upper_bound (d + 1, d + 1 + n, x[i].b) - d;
			ans = max (ans, p);
			d[p] = x[i].b;
		}
		cout << ans << endl;
	}

	return 0;
}

  

poj 1548 Robots

题意:在一个矩形区域内,一个机器人在左上角出发,每次只能向右向下进行移动,在移动中清理垃圾,一直到右下角,给出所有垃圾的位置,求至少要多少个机器人才能清理完所有垃圾?

题解:

chain : pi ≤ pj  (pi.x <= pj.x && pi.y <= pj.y)

antichain : (pi.x <= pj.x && pi.y > pj.y) || (pi.x > pj.x && pi.y <= pj.y)

如果按照p.x排序,那么也就是求关于y的最长下降子序列,需要注意的是当x 想等的时候按照要按照y从小到大排序。

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int N = 1e5 + 7;
struct node {int x, y;} p[N];
int n, x, y, d[N];

bool cmp (node a, node b) {
	return a.x < b. x || (a.x == b.x && a.y < b.y);
}

int main () {
	while(true) {
		n = 0;
		while (scanf ("%d%d", &x, &y) != EOF) {
			if (x == 0 && y == 0) break;
			if (x == -1 && y == -1) return 0;
			p[++n] = (node) {x, y};
		}
		sort (p + 1, p + 1 + n, cmp);
		memset (d, 127, sizeof d);
		int ans = 0;
		for (int i = n; i >= 1; --i) {
			int pos = lower_bound(d + 1, d + 1 + n, p[i].y) - d;
			ans = max (ans, pos);
			d[pos] = p[i].y;
		}
		cout << ans << endl;;
	}
	return 0;
}

  

总结:

Dilworth,虽然不懂证明但是确实感受到了一波他的正确性,一般将她转化成DAG,在辨别可比性的时候,把它弄在平面上会比较直观,还有在写cmp的时候要想清楚……

时间: 2024-08-07 19:26:06

Dilworth定理的相关文章

codevs1044:dilworth定理

http://www.cnblogs.com/submarine/archive/2011/08/03/2126423.html dilworth定理的介绍 题目大意:求一个序列的lds 同时找出这个序列最少用几个下降子序列覆盖 题解:第一问当然非常简单,第二问不会了..准备去搬最小路径覆盖模板 结果百度了一下发现由dilworth定理可知答案就是 lis的长度...跪 代码: #include<stdio.h> #include<string> #include<strin

bzoj 3997 Dilworth定理

看到这道题感觉像是网络流,如果没有权值,可以用DAG最小路径覆盖,有权值,感觉可以求一个上下界最小可行流,但内存卡了....时间估计也悬. 正解要用到一些数学知识,这里梳理一下: 定义: 偏序关系: 满足自反,反对称,传递的关系是自反关系 链: 偏序集A的一个子集B,并且满足B中元素两两可比 反链: 偏序集A的一个子集B,并且满足B中元素两两不可比 集合的划分: 集合A的划分是很多个集合,这些集合的交集为空,并集为A Dilworth定理: 偏序集的最长反链的大小等于最小链划分 另一个定理: 偏

dilworth定理的通俗讲解

度娘定义:在数学理论中的序理论与组合数学中,Dilworth定理根据序列划分的最小数量的链描述了任何有限偏序集的宽度.其名称取自数学家Robert P. Dilworth. 反链是一种偏序集,其任意两个元素不可比:而链则是一种任意两个元素可比的偏序集.Dilworth定理说明,存在一个反链A与一个将序列划分为链族P的划分,使得划分中链的数量等于集合A的基数.当存在这种情况时,对任何至多能包含来自P中每一个成员一个元素的反链,A一定是此序列中的最大反链.同样地,对于任何最少包含A中的每一个元素的一

【codevs1044】导弹拦截问题与Dilworth定理

题目描述 Description 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度.某天,雷达捕捉到敌国的导弹来袭.由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹. 输入描述 Input Description 输入导弹依次飞来的高度(雷达给出的高度数据是不大于30000的正整数) 输出描述 Output Description 输出这套系统最多能拦截多少导弹

(转载)偏序集的Dilworth定理学习

导弹拦截是一个经典问题:求一个序列的最长不上升子序列,以及求能最少划分成几组不上升子序列.第一问是经典动态规划,第二问直接的方法是最小路径覆盖, 但是二分图匹配的复杂度较高,我们可以将其转化成求最长上升子序列,其最大值即等于不上升子序列的最小划分数.这就涉及到组合数学中偏序集的 Dilworth定理.(第二问的贪心方法其实就是这个定理的证明过程) 其中第一问和第二问都可以用o(nlogn)的算法解决: #include<cstdio> #include<cstring> #incl

【PAT L2-014】列车调度(Dilworth定理)

[PAT L2-014]列车调度(Dilworth定理) L2-014. 列车调度 时间限制 300 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 陈越 火车站的列车调度铁轨的结构如下图所示. Figure 两端分别是一条入口(Entrance)轨道和一条出口(Exit)轨道,它们之间有N条平行的轨道.每趟列车从入口可以选择任意一条轨道进入,最后从出口离开.在图中有9趟列车,在入口处按照{8,4,2,5,3,9,1,6,7}的顺序排队等待进入.如

【POJ1548】Robots Dilworth定理(偏序集定理2)

题意: 有一些位置有垃圾,让机器人从左上角开始走,只能往右或者往下,问最少走多少次可以清理完所有垃圾. 题解: 一看就是网络流经典题,或者说是二分图-最小路径覆盖:但是现在毕竟是在做一些贪心,这道题用的是一种贪心相关定理,Dilworth定理. 这道题可以理解为部分两点之间有偏序(可走的关系),呃,可以视为当xa<=xb&&ya<=yb时有偏序,那么姑且认为反之则为反偏序,那么定义一条链为由n-1个偏序连接起来的n个点,那么答案就是"最长反链的大小. 比如题中的数据1

BZOJ 3997 TJOI2015 组合数学 Dilworth定理

题目大意:给定一个网格图,每次从左上角出发,只能往右或往下走,最后到达右下角,每个格子有最低经过次数,问最少走几次 Dilworth定理:DAG的最小链覆盖=最大点独立集 最小链覆盖指选出最少的链(可以重复)使得每个点都在至少一条链中 最大点独立集指最大的集合使集合中任意两点不可达 此题中最大点独立集显然是一个集合满足集合中任意两点都是左下-右上的关系 DP一遍就能出解 复杂度O(Tmn) #include <cstdio> #include <cstring> #include

hdu1051(LIS | Dilworth定理)

这题根据的Dilworth定理,链的最小个数=反链的最大长度 , 然后就是排序LIS了 链-反链-Dilworth定理 hdu1051 #include <iostream> #include <stdio.h> #include <string.h> #include <math.h> #include <algorithm> #include <string> #include <queue> #include <