最小链覆盖——Dilworth定理
Dilworth定理
Dilworth定理,一言以蔽之,偏序集能划分成的最少的全序集个数等于最大反链的元素个数。
——————litble
狄尔沃斯定理(Dilworth’s theorem)亦称偏序集分解定理,是关于偏序集的极大极小的定理,该定理断言:对于任意有限偏序集,其最大反链中元素的数目必等于最小链划分中链的数目。此定理的对偶形式亦真,它断言:对于任意有限偏序集,其最长链中元素的数目必等于其最小反链划分中反链的数目,由偏序集P按如下方式产生的图G称为偏序集的可比图:G的节点集由P的元素组成,而e为G中的边,仅当e的两端点在P中是可比较的,有限全序集的可比图为完全图——————百科
二 偏序集中的概念
链 : D 中的一个子集 C 满足 C 是全序集 及C中所有元素都可以比较大小
反链 : D 中的一个子集 B 满足 B 中任意非空子集都不是全序集 即所有元素之间都不可以比较大小
链覆盖 : 若干个链的并集为 D ,且两两之间交集为 ∅
反链覆盖 : 若干个反链的并集为 D ,且两两之间交集为∅
最长链 : 所有链中元素个数最多的 (可以有多个最长链)
最长反链 : 所有反链中元素个数最多的 (可以有多个最长反链
偏序集高度 : 最长链的元素个数
偏序集宽度 : 最长反链中的元素个数
最小链覆盖(使链最少)= 最长反链长度 = 偏序集宽度
最小反链覆盖=最长链长度=偏序集深度
Dilworth定理在序列中的应用
洛谷P1020 导弹拦截
思路:
题目中说以后每一发都不能高于前一发,我们能拦截的导弹高度是非递增序列,第一问显然就是最大非递增序列的长度,因为这里范围比较大,所以我们单调队列+二分优化DP。
第二问要最少配备多少套拦截系统,就是问这个序列最少可以划分为多少个非递增序列,根据Dilworth定理,我们只需求最长上升子序列的长度就是答案。
int a[N];
int d[N];
int main(){int tot = 0;while(scanf("%d",&a[++tot]) == 1){}tot --;int len = 1;d[1] = a[1];rep(i,2,tot){if(a[i] <= d[len]) d[++len] = a[i];else {int pos = upper_bound(d +1,d + len + 1,a[i],greater<int>()) - d;d[pos] = a[i];}}cout << len<<endl;d[1] = a[1];len = 1;rep(i,2,tot){if(a[i] > d[len]) d[++len] = a[i];else {int pos = lower_bound(d+1,d +len + 1,a[i]) - d;d[pos] = a[i];}}cout << len;
}
Codeforce 1296 E
给你一个字符串,然后你可以数字给每个位置的字符染色,只有相邻的颜色不同的字符才可以交换位置。问你是否最小用多少颜色使得这个字符串经过数次交换后呈字典序从小到大分布。然后输出染色的结果。
思路:
题目就是问你最少用多少个最长不下降子序列凑成这个序列。根据Dilworth定理可得,是最大反链的个数,即最长下降子序列的长度。然后构造每个字符的颜色就是当前以它为结尾的字符串中最长下降子序列的长度。
int r[26];
int vis[N];
int main(){memset(vis,0,sizeof vis);int n;cin >> n;string s;cin >> s;int M = -INF;for(int i = 0;i < n;++i){int d = 0;for(int j = s[i] - 'a' + 1;j < 26;++j){d = max(d,r[j]);}r[s[i]-'a'] = d + 1;vis[i] = d + 1;M = max(M,d + 1);}cout << M<<endl;for(int i = 0;i < n;++i) cout << vis[i] <<' ';
}
牛客挑战赛36 C-纸飞机
思路:
题意显然问去除一个数后剩余的序列最少可以被多少个严格递减序列组成。
根据Dilworth定理,我们求反链的最大长度,即不严格递减序列的最大长度。
如果我们每删去一个数求一次肯定会超时,这样想,我们求出原来序列的最长不递减序列,每删去一个数,是否会影响原来序列的最长不递减序列的长度?
如果这个数不在原来的最长不递减序列中或者这个数所在的位置不唯一(1 3
2
4),则并不会影响原来的结果,而如果这个数在里面且唯一,则答案会减一。
那如果判断呢?
由于范围比较大,n2n^2n2肯定超时,所以我们用树状数组优化,dp[i]dp[i]dp[i]代表着以iii结尾的最大长度,假设所谓最大长度为ansansans。求完后,我们倒序判断一个数是否在所求的最长不递减序列中。我们增加辅助数组axaxax,ax[i]ax[i]ax[i]代表最长序列中第iii个位置的数的最大值,vis[i]vis[i]vis[i]表示第iii个数是否在最长序列中。
首先dp[i]=ansdp[i]=ansdp[i]=ans的数肯定在最长序列中,然后对于第iii个数字,如果a[i]<=ax[dp[i]+1]a[i]<=ax[dp[i]+1]a[i]<=ax[dp[i]+1],那么说明第iii个数在最长序列中,我们更新最大的ax[dp[i]]ax[dp[i]]ax[dp[i]]值,并开一numnumnum数组统计最长序列中每个位置的数有几个。
最后判断输出即可。
int n;
int dp[N];
int c[N],ax[N];
int a[N],b[N];
bool vis[N];int num[N];
void modify(int x,int y){for(;x <= n;x += x&(-x)){c[x] = max(c[x],y);}
}
int getMax(int x){int ans = 0;for(;x;x -= x&(-x)){ans = max(ans,c[x]);}return ans;
}
int main(){n = read();rep(i,1,n) a[i] = b[i] = read();sort(b + 1,b + n + 1);int m = unique(b + 1,b + n + 1) - b - 1;rep(i,1,n) a[i] = lower_bound(b+1,b+m+1,a[i]) - b;int ans = 0;rep(i,1,n){dp[i] = getMax(a[i]) + 1;modify(a[i],dp[i]);ans = max(ans,dp[i]);}cout <<ans << endl;ax[ans+1] = INF;fori(i,n,1){if(a[i] <= ax[dp[i]+1]){vis[i] = 1;num[dp[i]] ++;ax[dp[i]] = max(ax[dp[i]],a[i]);}}rep(i,1,n){if(num[dp[i]] == 1&&vis[i]) cout<<ans-1<<' ';else cout<<ans<<' ';}
}
Dilworth定理在DAG中的应用
DAG中,有如下的一些定义和性质:
链:一条链是一些点的集合,链上任意两个点x, y,满足要么 x 能到达 y ,要么 y 能到达 x 。
反链:一条反链是一些点的集合,链上任意两个点x, y,满足 x 不能到达 y,且 y 也不能到达 x。
一个定理:最长反链长度 = 最小链覆盖(用最少的链覆盖所有顶点)
对偶定理:最长链长度 = 最小反链覆盖
那么我们要求出的就是这个有向无环图的最小链覆盖了。
最小链覆盖即路径可以相交的最小路径覆盖。
\qquad \qquad\qquad\qquad\qquad ————by Eirlys_North
**DAG的最小路径覆盖**
定义:在一个有向图中,找出最少的路径,使得这些路径经过了所有的点。
最小路径覆盖分为最小不相交路径覆盖和最小可相交路径覆盖。
最小不相交路径覆盖:每一条路径经过的顶点各不相同。如图,其最小路径覆盖数为3。即1->3>4,2,5。
最小可相交路径覆盖:每一条路径经过的顶点可以相同。如果其最小路径覆盖数为2。即1->3->4,2->3>5。
特别的,每个点自己也可以称为是路径覆盖,只不过路径的长度是0。
\qquad \qquad\qquad\qquad\qquad ——justPassBy
对于DAG最小不相交路径覆盖有个定理:
有向无环图G的最小路径点覆盖包含的路径条数,等于nnn减去拆点二分图G2的最大匹配数。
而对于DAG最小可相交路径点覆盖:
我们把图中所有间接连通的点在原图中给他连一条边让它直接连通,那么这个问题就变成了上述DAG最小不相交路径点覆盖了。所以我们先对有向图传递闭包(偏序关系补全),然后n2n^2n2建立二分图,最后求最大匹配即可。
———————————————————————————————————
bzoj1143 祭祀
思路:
题目很显然让我们求一个最大的集合,集合中的点两两之间不能相互到达,这显然就是让求最大反链的长度,最长反链的长度 = 最小链覆盖。
即DAG最小可相交路径覆盖,先传递闭包,然后拆点二分图最大匹配即可。
int w[220][220];
int head[220],tot;
bool vis[205];
int match[205];
struct Edge{int next;int to;
}edge[N];
inline void add(int from,int to){edge[++tot].next = head[from];edge[tot].to = to;head[from] = tot;
}
void floyd(int n){rep(k,1,n){rep(i,1,n){rep(j,1,n){w[i][j] |= w[i][k]&w[k][j];}}}
}
bool dfs(int x){for(int i = head[x];i;i = edge[i].next){int y = edge[i].to;if(!vis[y]){vis[y] = 1;if(!match[y]||dfs(match[y])){match[y] = x;return true;}}}return false;
}
int main(){int n = read(),m = read();rep(i,1,m){int u = read(),v = read();w[u][v] = 1;}floyd(n);//传递闭包rep(i,1,n){rep(j,1,n){if(w[i][j]) add(i,j+n);}}int ans = 0;rep(i,1,n){//二分图最大匹配memset(vis,0,sizeof vis);if(dfs(i)) ans ++;}cout <<n - ans<<endl;
}
本文查阅诸多网上博客资料所写,如有冒犯请留言。
最小链覆盖——Dilworth定理相关推荐
- 最小路径覆盖与最小链覆盖 Dilworth定理:最小链覆盖等于最长反链(详细证明与经典例题)
一.最小路径覆盖 定义 最小路径覆盖就是指在有向无环图中,用最少的.不相交的简单路径覆盖图中的所有点. 解法 ①将原图中的每个点拆点,(将点u拆成u与u+n): ②将原图中的每条边 <u,v&g ...
- BZOJ.4160.[NEERC2009]Exclusive Access 2(状压DP Dilworth定理)
BZOJ DAG中,根据\(Dilworth\)定理,有 \(最长反链=最小链覆盖\),也有 \(最长链=最小反链划分数-1\)(这个是指最短的最长链?并不是很确定=-=),即把所有点划分成最少的集合 ...
- 【学习笔记】Dilworth 定理的构造性证明
发现自己并不会 Dilworth 定理的构造性证明(原题要求输出方案),于是去 Wiki 上学习了一下.下文是我参照 Wiki 上的证明思路口胡的一个证明. 附例题:Codeforces 590E D ...
- Dilworth 定理
Dilworth 定理 对于偏序集 DDD,我们有若干概念: 链:DDD 中的一个子集 CCC 满足 CCC 中任意两个元素都可比,即构成全序集. 反链:DDD 中的一个子集 BBB 满足 BBB 中 ...
- Dilworth定理的简单应用(导弹拦截题解)
写题时遇到一个计算导弹拦截系统的题解使用了Dilworth定理,浅写下个人理解. 一.百科解释 狄尔沃斯定理(Dilworth's theorem)亦称偏序集分解定理,是关于偏序集的极大极小的定理,该 ...
- 最长反链=最小链覆盖(证明+解析)
最长反链与最小链覆盖 转自:http://vfleaking.blog.163.com/blog/static/1748076342012918105514527/ 膜拜! 大前提:在有向无环图中 链 ...
- [bzoj1143][CTSC2008]祭祀river——DAG上最长反链,Dilworth定理,最大二分图匹配,Floyd
题目大意: 给定一个DAG图,求最长反链(即一个点集,其中任意点两两不可以相互到达). 思路: 一开始我其实是想用求最大独立集的方法去求的.但是并不会(好像也过不去). 题目所要求的是最长反链,需要用 ...
- BZOJ1143[CTSC2008]祭祀river 偏序集及Dilworth定理
这里讲一下我对偏序集的认识 如果有偏差可以评论我 我会修改 一:定义 (度娘上copy来的 不想看的可以跳过 设R是非空集合A上的一个二元关系,若R满足: 自反性.反对称性.传递性,则称R为A ...
- BZOJ.1143.[CTSC2008]祭祀(Dilworth定理 最大流ISAP)
题目链接 题目是求最长反链,反链指点集内任意两点不能互相到达. 根据Dilworth定理,在DAG中,\[最长反链 = 最小路径覆盖 = V - 最大匹配数\] 用Floyd求一遍传递闭包后,在所有可 ...
最新文章
- 亿景WideLink系统与微软统一通信的整合
- Android学习——自定义控件(二)
- MIT_18.03_微分方程_Fourier_Series_傅里叶级数_Notes
- [!] Attempt to read non existent folder `***********`
- LeetCode MySQL 1890. 2020年最后一次登录(year)
- Vue.js 2.5 发布,而这个会玩的团队已经自研出用 Vue 开发小程序的框架了
- python实现最大公共子序列
- html优化的基本网页布局,网站页面标题的SEO优化及布局要点
- Atitit 组织架构的如何划分 划分方法attilax大总结
- mysql数据库证件脱敏_mysql 数据库脱敏
- 手机WIFI共享 打造便携式WIFI热点
- 带你十分钟做出一个自己的手机APP
- 人人都懂设计模式--Everybody Know Design Patterns : How to comprehend Design Patterns from daily life
- python-给登记照换底色(蓝底变红底)
- 极简OpenFoam编程
- 小狗钱钱:钱钱的金钱语录
- pythoninstaller打包 其他电脑无法运行_Pyininstaller一个软件包故障坑,Pyinstaller,打包,失败,的...
- 中望CAD的lisp编辑器_巧用中望CAD2017自定义工具选项板
- 凝眸笑靥,又是一年寂寥春
- IE6兼容性问题及解决办法汇总